タイトル: Regis Takeaway-Day02
略リンク: '1'
日付: 2023-04-1 19:30:00
セント レジス テイクアウト - Day02
授業内容
- 充実したログイン機能
- 新入社員
- 従業員情報ページングクエリ
- 従業員アカウントの有効化/無効化
- 従業員情報を編集する
フロントエンドページの効果がどのように達成されるかを分析する
左右をクリックするとルートが変更されるのはなぜですか?
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-WwJYwseg-1688460908030)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304092100003.png)]
まずはメニューの表示方法ですが、なぜメニューをクリックすると右側が変化するのかを見てみましょう。
まずはメニューの表示方法
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-a6J6csVc-1688460908031)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304092101695.png)]
VUE オブジェクトを作成するとき、data() の位置に menuList: [] を準備します。menuList: [] は配列オブジェクトです。
各JSONデータは配列オブジェクトに配置され、各JSONデータにはID名URLアイコン(アイコン)が含まれます。上記は定義ではなくデータの準備だけですので、メニューの位置に表示することができます
<script>
new Vue({
el: '#app',
data() {
return {
defAct: '2',
menuActived: '2',
userInfo: {
},
menuList: [
// {
// id: '1',
// name: '门店管理',
// children: [
{
id: '2',
name: '员工管理',
url: 'page/member/list.html',
icon: 'icon-member'
},
{
id: '3',
name: '分类管理',
url: 'page/category/list.html',
icon: 'icon-category'
},
{
id: '4',
name: '菜品管理',
url: 'page/food/list.html',
icon: 'icon-food'
},
{
id: '5',
name: '套餐管理',
url: 'page/combo/list.html',
icon: 'icon-combo'
},
{
id: '6',
name: '订单明细',
url: 'page/order/list.html',
icon: 'icon-order'
}
// ],
// },
],
iframeUrl: 'page/member/list.html',
headTitle: '员工管理',
goBackFlag: false,
loading: true,
timer: null
}
},
computed: {
},
created() {
const userInfo = window.localStorage.getItem('userInfo')
if (userInfo) {
this.userInfo = JSON.parse(userInfo)
}
this.closeLoading()
},
beforeDestroy() {
this.timer = null
clearTimeout(this.timer)
},
mounted() {
window.menuHandle = this.menuHandle
},
methods: {
logout() {
logoutApi().then((res)=>{
00
if(res.code === 1){
localStorage.removeItem('userInfo')
window.location.href = '/backend/page/login/login.html'
}
})
},
goBack() {
// window.location.href = 'javascript:history.go(-1)'
const menu = this.menuList.find(item=>item.id===this.menuActived)
// this.goBackFlag = false
// this.headTitle = menu.name
this.menuHandle(menu,false)
},
menuHandle(item, goBackFlag) {
this.loading = true
this.menuActived = item.id
this.iframeUrl = item.url
this.headTitle = item.name
this.goBackFlag = goBackFlag
this.closeLoading()
},
closeLoading(){
this.timer = null
this.timer = setTimeout(()=>{
this.loading = false
},1000)
}
}
})
</script>
menuList: [ menuList: [] 是一个数组对象 数组对象 //120行
{ 里面放着一个个JSON数据
id: '2', 每一个JSON数据里面又放着id name url icon(图标)
name: '员工管理',
url: 'page/member/list.html',
icon: 'icon-member'
},
{
id: '3',
name: '分类管理',
url: 'page/category/list.html',
icon: 'icon-category'
},
{
id: '4',
name: '菜品管理',
url: 'page/food/list.html',
icon: 'icon-food'
},
{
id: '5',
name: '套餐管理',
url: 'page/combo/list.html',
icon: 'icon-combo'
},
{
id: '6',
name: '订单明细',
url: 'page/order/list.html',
icon: 'icon-order'
}
// ],
// },
],
名称としては「従業員管理」、「カテゴリ管理」、「料理管理」、「パッケージ管理」、「注文内容」などがあり、下図に示すものに対応します。
上記はデータの準備であり、メニューの位置に表示できる定義ではありません。
次に、メニューの位置を表示する方法
39 行目に進み、el-menu コンポーネントの下で v-for を使用して、menuList をトラバースしていることを示してください。
<el-submenu :index="item.id" v-if="item.children && item.children.length>0">
ここの v-if は確立されませんが、64 行目の分岐 <el-menu-item v-else :index="item.id" @click="menuHandle(item,false)"> が実行され、その後 {{item.name}} item.name を表示できます
<el-menu //菜单组件
:default-active="defAct"
:unique-opened="false"
:collapse-transition="false"
background-color="#343744"
text-color="#bfcbd9"
active-text-color="#f4f4f5"
> //item不是固定写法
<div v-for="item in menuList" :key="item.id"> //v-for表示在遍历 遍历menuList
//判断item里面有没有children属性和children属性的length是否大于0
//我们往下看到第126那里的每一项都没有我们的children
// 但是会执行第64行<el-menu-item v-else :index="item.id" @click="menuHandle(item,false)">这个分支 // 然后就可以把第66行的item.name给展示出来 如果我们把id修改成Id
<el-submenu :index="item.id" v-if="item.children && item.children.length>0">
<template slot="title">
<i class="iconfont" :class="item.icon"></i>
<span>{
{item.name}}</span>
</template>
<el-menu-item
v-for="sub in item.children"
:index="sub.id"
:key="sub.id"
@click="menuHandle(sub,false)"
>
<i :class="iconfont" :class="sub.icon"></i>
<span slot="title">{
{sub.name}}</span>
</el-menu-item
>
</el-submenu>
//64行 <el-menu-item v-else :index="item.id" @click="menuHandle(item,false)">
<i class="iconfont" :class="item.icon"></i>
//66行 <span slot="title">{
{item.name}}</span> //把item.name给展示出来
</el-menu-item>
</div>
</el-menu>
したがって、表示されるのは次の名前です
名前をIDに変更すると
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-VueK0LVa-1688460908036)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304092342644.png)]
再起動リフレッシュ
なぜ Id なのかというと、このオブジェクト配列 menuList:[] によって決定されるからです。
`new Vue({
el: '#app',
data() {
return {
defAct: '2',
menuActived: '2',
userInfo: {},
menuList: [
// {
// id: '1',
// name: '门店管理',
// children: [
{
id: '2',
name: '员工管理',
url: 'page/member/list.html',
icon: 'icon-member'
},
{
id: '3',
name: '分类管理',
url: 'page/category/list.html',
icon: 'icon-category'
},
{
id: '4',
name: '菜品管理',
url: 'page/food/list.html',
icon: 'icon-food'
},
{
id: '5',
name: '套餐管理',
url: 'page/combo/list.html',
icon: 'icon-combo'
},
{
id: '6',
name: '订单明细',
url: 'page/order/list.html',
icon: 'icon-order'
}
// ],
// },
],
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-L8eI3NKi-1688460908040)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304092344576.png)]
3番目: メニューをクリックすると、右側が変わります
http://localhost:8080/backend/index.html
これらのメニューには実際に @click イベントが追加されており、メニューをクリックすると、menuHandle() メソッドが実行されます。
<el-menu-item v-else :index="item.id" @click="menuHandle(item,false)">
次に項目を false に渡すと、196 行目に menuHandle() メソッドが見つかります。
menuHandle(item, goBackFlag) {
this.loading = true
this.menuActived = item.id
this.iframeUrl = item.url
this.headTitle = item.name
this.goBackFlag = goBackFlag
this.closeLoading()
},
メニューをクリックすると、menuHandle() メソッドが実行されます。ここで最も重要なことは this.iframeUrl = item.url です。
ここでのURLは以下のURL(128行目)であり、クリックメニューのURLとなります。
menuList: [
// {
// id: '1',
// name: '门店管理',
// children: [
{
id:'2',
name : '员工管理',
url: 'page/member/list.html',
icon: 'icon-member'
},
{
id: '3',
name: '分类管理',
url: 'page/category/list.html',
icon: 'icon-category'
},
{
id: '4',
name: '菜品管理',
url: 'page/food/list.html',
icon: 'icon-food'
},
{
id: '5',
name: '套餐管理',
url: 'page/combo/list.html',
icon: 'icon-combo'
},
{
id: '6',
name: '订单明细',
url: 'page/order/list.html',
icon: 'icon-order'
}
// ],
// },
],
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-FGiI0VQ9-1688460908045)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304100024943.png)]
これは、iframeUrl を通じて新しいページを表示します。
158 行目で定義された iframeUrl
iframeUrl: 'page/member/list.html',
iframeUrl はどこで使用されますか?
89行目で使用
<iframe></iframe>
これは新しいページを表示するために使用されます。このページはどこから来たのか
<iframe //用来展示一个新的页面
id="cIframe"
class="c_iframe"
name="cIframe"
:src="iframeUrl"
width="100%"
height="auto"
frameborder="0"
v-show="!loading"
></iframe>
これはページに穴を掘るのと同じです
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-HHPZH34n-1688460908048)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304100031207.png)]
そして、このページはどこから来たのでしょうか?
<iframe
id="cIframe"
class="c_iframe"
name="cIframe"
:src="iframeUrl" 这个地方传进什么数据 展示的就是什么数据
width="100%"
height="auto"
frameborder="0"
v-show="!loading"
></iframe>
ログイン後にカテゴリ管理などではなく従業員管理が表示されるのはなぜですか?
これは、iframeUrl に次の初期値を与えるためです。
iframeUrl: 'page/member/list.html',
メニューをクリックすると、実際には URL が切り替わります。
menuHandle(item, goBackFlag) {
this.loading = true
this.menuActived = item.id
this.iframeUrl = item.url
this.headTitle = item.name
this.goBackFlag = goBackFlag
this.closeLoading()
},
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-lsGTKVNm-1688460908051)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131532890.png)]
たとえば、最初のページを次のように変更します。
iframeUrl: 'http://www.itcast.c
再起動リフレッシュ
したがって、メニューをクリックすると、実際には URL アドレスが切り替わります。
そして、このURLアドレスはデータ作成時にすでに書き込まれています。
menuList: [
// {
// id: '1',
// name: '门店管理',
// children: [
{
id:'2',
name : '员工管理',
url: 'page/member/list.html',
icon: 'icon-member'
},
{
id: '3',
name: '分类管理',
url: 'page/category/list.html',
icon: 'icon-category'
},
{
id: '4',
name: '菜品管理',
url: 'page/food/list.html',
icon: 'icon-food'
},
{
id: '5',
name: '套餐管理',
url: 'page/combo/list.html',
icon: 'icon-combo'
},
{
id: '6',
name: '订单明细',
url: 'page/order/list.html',
icon: 'icon-order'
}
// ],
// },
],
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-k2oreBW7-1688460908054)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304100044727.png)]
異なるメニューは異なるページに対応しているため、特定のメニューをクリックすると、実際には対応するページに切り替わります。
1. ログイン機能の改善
1.1 問題分析
以前、バックグラウンドシステムの従業員ログイン機能の開発は完了しましたが、まだ問題が残っているので、次にその問題とその対処方法について説明します。
1). 現状
ユーザーがログインせずにシステムのホームページに直接アクセスした場合でも、通常どおりアクセスできます。
2). 理想的な効果
上記の設計は不合理です。私たちが確認したい効果は、ログインが成功した場合にのみシステム内のページにアクセスできるようにすることです。ログインがない場合、システム内のどのインターフェイスもログイン ページに直接ジャンプします。
では、それはどのように実現されるべきなのでしょうか?
これは、先ほど説明したフィルターとインターセプターを使用し、フロントエンドが開始したリクエストをフィルターとインターセプターでインターセプトし、ユーザーがログインしているかどうかを判断することで実現できます。ログインしていない場合は、プロンプトメッセージを返し、ログインページにジャンプします。 。
1.2 思考分析
フィルターの具体的な処理ロジックは次のとおりです。
A. このリクエストの URI を取得します。
B. このリクエストにアクセスする前にログインする必要があるかどうかを判断する
C. 必要がない場合は、直接解放します
D. ログイン状態を判断し、すでにログインしている場合は直接解放されます
E. ログインしていない場合は、ログインしていないという結果を返します
ログインしていない場合、どのような結果をフロントエンドに返す必要がありますか? 現時点では、フロントエンドがそれをどのように処理するかを確認できますか?
1.3 コードの実装
実装手順:
1. カスタム フィルター LoginCheckFilter を作成します。
2. アノテーション @ServletComponentScan をスタートアップ クラスに追加します
。 3. フィルターの処理ロジックを改善します。
1). ログイン検証フィルターを定義する
フィルター LoginCheckFilter をカスタマイズして Filter インターフェースを実装し、 doFilter メソッドで検証ロジックを完成させます。次に、上記の分析手順に従って、特定の関数コードの実装を完了します。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-tEBf2g8a-1688460908057)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131533933.png)]
package com.itheima.reggie.filter;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*检查用户是否已经完成登录*/
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//强转
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
log.info("拦截到请求:{}",request.getRequestURI());
//放行
filterChain.doFilter(request,response);
}
}
リブート
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-JcYZhW6y-1688460908060)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131533957.png)]
リフレッシュする
コードの説明:
一つ説明して
このコードは、Java Web アプリケーションのフィルター (Filter) です。フィルタは、リクエストがターゲットのサーブレット/JSP に到達する前にリクエストまたはレスポンスを前処理するため、実際のリクエストが処理される前に一部の操作が実行されます。
このフィルタの機能は、URL がユーザーの認証情報 (セッション ID、トークンなど) にログインするために使用されているかどうかをチェックすることで、ユーザーがログインしているかどうかを確認することです。ユーザーがログインしていない場合、フィルターはユーザーをログイン ページにリダイレクトします。ユーザーがすでにログインしている場合、リクエストは次のハンドラーに渡されます。
具体的には、このフィルターは Filter インターフェースの doFilter メソッドを実装します。このメソッドは、ServletRequest 型と ServletResponse 型のパラメータを受け取り、型変換によって HttpServletRequest 型と HttpServletResponse 型に変換します。次に、リクエストが傍受されたことを示すログを出力し、リクエストと応答のオブジェクトを FilterChain に渡します。最後に、フィルター チェーンは要求オブジェクトと応答オブジェクトを次のハンドラーに渡します。
つまり、このフィルタは非常に便利なツールであり、ターゲットのサーブレット/JSP に到達する前にユーザーのリクエストを前処理して、ユーザーがログインを完了して承認されていることを確認し、それによって Web アプリケーションのセキュリティを保護できます。
解説2
Java Web アプリケーションを使用する場合、ユーザーがログインして承認されていることを確認する必要があります。そうしないと、特別な権限が必要なページにアクセスできなくなります。それがこのコードの動作です。
このコードはフィルター (Filter) を実装しており、ターゲットのサーブレット/JSP に到達する前にリクエストを前処理します。ユーザーがすでにログインしているかどうかを確認し、ログインしていない場合は、ユーザーがログインを完了できるようにログイン ページにリダイレクトし、特別な権限が必要なページへのアクセスを再試行します。
このフィルタは、要求された URL をチェックし、その URL にセッション ID やトークンなどのユーザーの認証情報が含まれている場合、そのユーザーはログインしていると見なされます。ユーザーがログインを完了していない場合は、ユーザーがログインを完了するためのログイン ページにリダイレクトされます。
このフィルターの実装は比較的単純で、Filter インターフェイスに doFilter メソッドを実装します。リクエストが到着すると、リクエストを HttpServletRequest オブジェクトに変換し、ログインが完了したかどうかを確認します。ログインがすでに完了している場合は、要求オブジェクトと応答オブジェクトを次のハンドラーに渡します。ログインが完了していない場合は、ユーザーはログイン ページにリダイレクトされます。
全体として、このフィルターは、ユーザーがログインして承認されていることを確認して、Web アプリケーションを保護するための便利なツールです。
解説3
このコードは Java Web アプリケーションのフィルター (Filter) であり、その機能は、ユーザーが Web ページにアクセスする前にユーザーがログイン操作を完了したかどうかを確認することです。
コードでは、@WebFilter アノテーションが使用され、フィルターの名前は「loginCheckFilter」として指定され、すべての URL、つまり「/*」に適用されます。
doFilter() メソッドでは、受信した ServletRequest オブジェクトと ServletResponse オブジェクトを HttpServletRequest オブジェクトと HttpServletResponse オブジェクトに変換し、現在のリクエストの URL アドレスを記録し、最後にさらなる処理のためにリクエスト オブジェクトと応答オブジェクトを FilterChain に渡します。
フィルターの機能はインターセプターに似ています。ユーザーが Web ページにアクセスすると、フィルターはまずリクエストをインターセプトし、ユーザーがログインしているかどうかを確認します。ユーザーがログイン操作を完了すると、フィルターはリクエストを解放して許可します。ユーザーはページへのアクセスを継続できます。ユーザーがログインしていない場合、フィルタはログイン ページにリダイレクトし、ページに進む前にユーザーにログインを要求します。
一般に、このコードの役割は、Web アプリケーション内の機密リソースを保護し、ログイン操作を完了したユーザーのみがこれらのリソースにアクセスできるようにして、システムのセキュリティを向上させることです。
理解: このコードに強制転送があるのはなぜですか
このコードでは、ServletRequest オブジェクトと ServletResponse オブジェクトを HttpServletRequest オブジェクトと HttpServletResponse オブジェクトに変換します。これは、Filter インターフェイスの doFilter メソッドが ServletRequest オブジェクトと ServletResponse オブジェクトを受け取り、HTTP リクエストと応答関連の情報を取得するには HttpServletRequest オブジェクトと HttpServletResponse オブジェクトを使用する必要があるためです。
ServletRequest と ServletResponse は、Java サーブレット仕様で定義されているインターフェイスで、HTTP リクエストとレスポンスを処理する一般的な方法を提供します。ただし、HttpServletRequest および HttpServletResponse インターフェイスで定義されている getParameter や getAttribute など、HttpServletRequest および HttpServletResponse オブジェクトの一部のメソッドが欠落しています。
したがって、これらの特定のメソッドを使用できるようにするには、ServletRequest オブジェクトと ServletResponse オブジェクトを HttpServletRequest オブジェクトと HttpServletResponse オブジェクトにキャストして、これらの特定のメソッドを使用できるようにする必要があります。ただし、キャストする前に、リクエストが実際に HTTP リクエストであることを確認する必要があります。そうしないと、キャストによって型変換例外が発生する可能性があります。
2 つのアノテーション: @WebFilter と @Slf4j の説明
@WebFilter アノテーションは、クラスをフィルター (Filter) としてマークするために使用され、フィルターの名前 (filterName) と URL パターン (urlPatterns) を指定できます。この例では、フィルターの名前を「loginCheckFilter」として設定し、URL パターンを「/*」として指定します。つまり、すべてのリクエストをインターセプトします。
@Slf4j アノテーションは、Lombok フレームワークで提供されるアノテーションの 1 つで、ロギング コードを簡素化するために使用されます。コンパイル時に「log」と呼ばれるロガーが自動的に生成され、ログに使用できます。この例では、log.info メソッドを使用して情報を記録します。
これらのアノテーションは、コードを記述し、関数をより便利に実装するのに役立ちます。@WebFilter アノテーションを使用すると、フィルターを定義し、インターセプトする必要があるリクエストを指定することが簡単になります。@Slf4j アノテーションは、ロギング機能をより便利に実装するのに役立ちます。
コードの各行の詳細な説明
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")
このコード行は、@WebFilter 注釈を使用してフィルターを宣言し、フィルターの名前を「loginCheckFilter」として指定し、それをすべての URL (つまり「/*」) に適用します。
@Slf4j
このコード行では、Lombok が提供する @Slf4j アノテーションを使用して、ログ情報の出力に使用できる log という名前のログ オブジェクトを自動的に生成します。
public class LoginCheckFilter implements Filter {}
このコード行は doFilter() メソッドの宣言です。このメソッドは Filter インターフェースのメソッドであり、ユーザー要求をインターセプトして処理するために使用されます。
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
このコード行は、受信した ServletRequest オブジェクトと ServletResponse オブジェクトを、後続のリクエストと応答の処理のために HttpServletRequest オブジェクトと HttpServletResponse オブジェクトに変換します。
log.info("拦截到请求:{}", request.getRequestURI());
このコード行は、以前に定義されたログ オブジェクトを使用してログ メッセージを出力し、現在のリクエストの URL アドレスを記録します。これは、後のデバッグや問題の特定に便利です。
filterChain.doFilter(request, response);
このコード行は、FilterChain オブジェクトの doFilter() メソッドを呼び出し、処理された要求オブジェクトと応答オブジェクトを次のフィルタまたはサーブレットに渡して処理します。他にフィルタがない場合は、処理のためにサーブレットに直接渡されます。このようにして、フィルターのチェーンが形成され、各リクエストが複数のフィルターによって処理されることが保証されます。
レビューフィルターフィルター
一つ説明して
HTTP Request --> Filter 1 --> Filter 2 --> ... --> Filter n --> Servlet --> HTTP Response
Java Web アプリケーションでは、フィルター (Filter) は HTTP 要求と応答を処理するために使用されるコンポーネントです。これらは、リクエストをインターセプトし、必要に応じてリクエストのパラメータ、ヘッダーまたは本文、および応答情報を変更するために使用されます。フィルタは、サーブレットの実行前または実行後、またはサーブレットの処理中に処理できます。
HTTP リクエストがサーブレット コンテナに到着すると、まず登録されているフィルタによってインターセプトされます。フィルターは、必要に応じてリクエストを変更したり、リクエストを次のフィルターに渡すことができます。すべてのフィルターがリクエストを処理すると、最終的なターゲット サーブレットが呼び出されます。サーブレットはリクエストを処理した後、同じフィルターチェーンを通じて処理されるレスポンスを生成します。レスポンスはフィルターごとに変更できます。
このフィルター チェーンの順序は web.xml ファイルで定義され、フィルターは動的に追加または削除できます。これにより、開発者は必要に応じてリクエスト処理プロセスをカスタマイズでき、より柔軟で複雑なアプリケーション機能が可能になります。
パッケージ: com.itheima.reggie.filter
import com.alibaba.fastjson.JSON;
import com.itheima.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 检查用户是否已经完成登录
*/
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter{
//路径匹配器,支持通配符
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//1、获取本次请求的URI
String requestURI = request.getRequestURI();// /backend/index.html
log.info("拦截到请求:{}",requestURI);
//定义不需要处理的请求路径
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**"
};
//2、判断本次请求是否需要处理
boolean check = check(urls, requestURI);
//3、如果不需要处理,则直接放行
if(check){
log.info("本次请求{}不需要处理",requestURI);
filterChain.doFilter(request,response);
return;
}
//4、判断登录状态,如果已登录,则直接放行
if(request.getSession().getAttribute("employee") != null){
log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("employee"));
filterChain.doFilter(request,response);
return;
}
log.info("用户未登录");
//5、如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
return;
}
/**
* 路径匹配,检查本次请求是否需要放行
* @param urls
* @param requestURI
* @return
*/
public boolean check(String[] urls,String requestURI){
for (String url : urls) {
boolean match = PATH_MATCHER.match(url, requestURI);
if(match){
return true;
}
}
return false;
}
}
AntPathMatcher 拡張機能:
概要: Spring で提供されるパスマッチャー。
ワイルドカードのルール:
シンボル 意味 ? キャラクターと一致する * 0 個以上の文字に一致します ** 0 個以上のディレクトリ/文字に一致します
2). コンポーネントのスキャンを有効にする
フィルタ設定の @WebFilter アノテーションをスキャンするには、ブートクラスにサーブレットコンポーネントスキャンのアノテーションを追加する必要があり、スキャン後、実行時にフィルタが有効になります。
@Slf4j
@SpringBootApplication
@ServletComponentScan
public class ReggieApplication {
public static void main(String[] args) {
SpringApplication.run(ReggieApplication.class,args);
log.info("项目启动成功...");
}
}
@ServletComponentScan の役割:
SpringBoot プロジェクトでは、このアノテーションをブート クラス/構成クラスに追加した後、プロジェクト内 (現在のパッケージとそのサブパッケージの下) の @WebServlet、@WebFilter、@WebListener アノテーションが自動的にスキャンされ、関連するサーブレットのコンポーネント。
1.4 機能テスト
直接入力する場合
http://localhost:8080/backend/login.html
時間
ログインインターフェースにジャンプします
http://localhost:8080/backend/page/login/login.html
動画のフロントエンド JS は実際のフロントエンドとは異なります
コードを記述した後、プロジェクトを再起動し、ブラウザのアドレス バーにシステム管理バックグラウンドのホームページを直接入力し、ログイン ページにジャンプできるかどうかを確認する必要があります。コード実行のプロセスをデバッグの形式で追跡することもできます。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-ncOlWYT3-1688460908063)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304021802532.png)]
フロントエンドコードについては、デバッグも実行できます。
F12 キーはブラウザーのデバッグ ツールを開き、前述した request.js を見つけて、request.js の応答インターセプターにブレークポイントを設定します。
2. 新入社員
2.1 需要分析
従業員情報はバックグラウンドシステムで管理でき、新規従業員を追加することでバックグラウンドシステムのユーザーを追加できます。[従業員の追加]ボタンをクリックすると、次のような新しいページに移動します。
フォーム情報を入力して「保存」ボタンをクリックすると、フォームのデータがサーバーに送信され、サーバーはデータを受け入れてデータベースにデータを保存する必要があります。
2.2 データモデル
新しい従業員を追加すると、実際には、新しいページに入力された従業員データが従業員テーブルに挿入されます。従業員テーブルのステータス フィールドは、ステータスが正常であることを示すデフォルト値 1 に設定されています。
ユーザー名は従業員のログイン アカウントであり、一意である必要があるため、一意の制約が従業員テーブルのユーザー名フィールドに追加されることに注意してください。
2.3 プログラム実行の流れ
コードを開発する前に、フロントエンド ページによって開始されたリクエストを組み合わせて、プログラム全体の実行プロセスを整理する必要があります。
A. [保存] ボタンをクリックすると、ページは ajax リクエストを送信し、新しい従業員ページに入力されたデータを json 形式でサーバーに送信します。リクエスト メソッドは POST、リクエスト パスは /employee です。
B. サーバー コントローラーはページによって送信されたデータを受信し、サービスを呼び出してデータを保存します。
C. サービスは Mapper を呼び出してデータベースを操作し、データを保存します
2.4 コードの実装
ユーザーの従業員情報を保存するためのsaveメソッドをEmployeeControllerに追加します。
A. 従業員を追加する場合、ボタン ページ プロトタイプの要件の説明で、従業員の初期デフォルト パスワード 123456 を設定し、そのパスワードを MD5 で暗号化する必要があります。
B. 従業員情報をまとめる際には、作成時刻、変更時刻、作成者、変更者の情報もカプセル化する(現在のログインユーザーをセッションから取得する)必要があります。
/*新增员工*/
@PostMapping
public R<String> save(@RequestBody Employee employee){
log.info("新增员工,员工信息:{}",employee.toString());
return null;
}
フロントエンド ページによって送信されたリクエストが save メソッドにリクエストでき、送信されたパラメータが従業員オブジェクトに送信できることを確認します。
@RequestBody: クライアント (フロントエンド) によって送信された JSON 文字列を取得し、ISON 文字列を Javabeen エンティティ クラスに変換するために使用されます。
@RespomseBody: JSON に変換された Javabeen エンティティ クラス
従業員: 従業員オブジェクトを使用して、フロントエンドによって渡されたリクエストパラメータを受け取ります(JSON形式)
R: 戻り値
概要説明1
このコードは、Spring フレームワークを使用して HTTP POST リクエストを処理し、リクエスト本文のデータを Employee オブジェクトにマップして従業員を追加するコントローラー メソッドです。
コードを 1 行ずつ説明しましょう。
@PostMapping
: これは、このメソッドを HTTP POST リクエスト メソッドにマップするために使用されるアノテーションです。これは、このメソッドがクライアントからの POST リクエストを処理することを示します。public R<String> save(@RequestBody Employee employee)
: これはメソッドの宣言です。Employee
リクエスト本文から抽出される type のパラメータを受け取ります。@RequestBody
アノテーションは、リクエスト本文から JSON データを取得してEmployee
オブジェクトに変換するように Spring フレームワークに指示します。log.info("新增员工,员工信息:{}", employee.toString())
: このコード行は、ログを使用して従業員を追加する操作を記録します。log.info()
メソッドは情報を出力するために使用され、プレースホルダーを使用しての戻り値をログ情報に挿入します{}
。employee.toString()
これにより、新しく追加された従業員の詳細をコンソールまたはログ ファイルで表示できるようになります。return null
: このメソッドはnull
値を返します。成功メッセージや新入社員の ID を返すなど、実際のニーズに応じて適切な応答を返すことができます。
したがって、このコントローラーの URL に HTTP POST リクエストを送信すると、リクエスト本文のデータがオブジェクトにマッピングされEmployee
、従業員の情報がログに出力されます。その後、メソッドはnull
応答として値を返します。ニーズに応じてメソッド本体を変更したり、適切なビジネス ロジックを実行したり、対応する結果を返したりすることができます。
概要説明2
このコードは、SpringBoot フレームワークに基づく従業員管理システムの新しい従業員機能のインターフェイスです。
このうち、@PostMapping アノテーションは、インターフェイスが POST リクエストのみを受け入れることを示します。@RequestBody アノテーションは、リクエスト本文内の JSON 形式のデータが Employee オブジェクトにバインドされていることを示します。Employee オブジェクトは、従業員 ID、名前、性別、役職などの属性を含む従業員の情報を表します。SpringBootはクライアントからPOSTリクエストを受信すると、リクエストボディのJSON形式データを対応するEmployeeオブジェクトに自動変換し、メソッドパラメータemployeeに代入します。
メソッド内で、log.info を使用して、新しく追加された従業員情報を出力します。最後に、インターフェイスによって返される型は R です。これはカスタム応答クラスを表します。R は応答結果を表し、String は応答メッセージの内容を表します。この例では、インターフェイスは null を返しました。実際のビジネス ニーズに応じて、Null を対応する応答結果に置き換える必要があります。
つまり、このコードの主な機能は、クライアントから送信された従業員情報を受信してデータベースに書き込み、ログを記録して応答結果を返すことです。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-GkG6Hg4I-1688460908065)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306051054661.png)]
/**
* 新增员工
* @param employee
* @return
*/
@PostMapping
public R<String> save(HttpServletRequest request,@RequestBody Employee employee){
log.info("新增员工,员工信息:{}",employee.toString());
//设置初始密码123456,需要进行md5加密处理
employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
//获得当前登录用户的id
Long empId = (Long) request.getSession().getAttribute("employee");
employee.setCreateUser(empId);
employee.setUpdateUser(empId);
employeeService.save(employee);
return R.success("新增员工成功");
}
コード説明1
このコードは、Spring フレームワークを使用して HTTP POST リクエストを処理し、従業員を追加するコントローラー メソッドです。
コードを 1 行ずつ説明しましょう。
@PostMapping
: これは、このメソッドを HTTP POST リクエスト メソッドにマップするアノテーションです。public R<String> save(HttpServletRequest request, @RequestBody Employee employee)
: これはメソッドの宣言です。HttpServletRequest request
と の2 つのパラメータを受け取りますEmployee employee
。@RequestBody
アノテーションは、リクエスト本文からデータを取得してEmployee
オブジェクトに変換するように Spring フレームワークに指示します。HttpServletRequest
パラメーターは、現在のリクエストに関する情報を取得するために使用されます。log.info("新增员工,员工信息:{}", employee.toString())
: このコード行は、ログを使用して従業員を追加する操作を記録します。従業員情報はemployee.toString()
文字列に変換され、ログ情報に挿入されます。employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()))
: このコード行は、従業員の初期パスワードを「123456」に設定し、MD5 で暗号化します。DigestUtils.md5DigestAsHex()
このメソッドは、バイト配列を MD5 ハッシュ文字列に変換します。employee.setCreateTime(LocalDateTime.now())
: このコード行は、現在の時刻を従業員の作成時刻として設定します。employee.setUpdateTime(LocalDateTime.now())
: このコード行は、現在の時刻を従業員の更新時刻として設定します。Long empId = (Long) request.getSession().getAttribute("employee")
: このコード行は、現在のセッションから「employee」という名前の属性を取得します。これは、現在ログインしているユーザーの ID を表します。employee.setCreateUser(empId)
およびemployee.setUpdateUser(empId)
: これら 2 行のコードは、現在ログインしているユーザーの ID を従業員の作成ユーザーおよび更新ユーザーとして設定します。employeeService.save(employee)
: このコード行は、新しく追加された従業員情報を保存するemployeeService
サービスのメソッドを呼び出します。save()
return R.success("新增员工成功")
: このコード行は、「新規従業員が成功しました」というメッセージを含む成功応答を返します。
要約すると、このコードは HTTP POST リクエストを処理し、リクエスト本文のデータをオブジェクトにマップし、Employee
初期パスワードの設定、作成時間と更新時間の設定、パスワードの設定などの一連の処理をオブジェクトに対して実行します。ユーザーの作成とユーザーの更新は待ちます。最後に、メソッドを呼び出してemployeeService
従業save()
員情報を保存し、成功した応答メッセージを返します。
コード解説2
このコードは、SpringBoot フレームワークに基づく従業員管理システムの新しい従業員機能のインターフェイスであり、前のコードと比較してビジネス ロジックの処理が追加されています。
このうち、@PostMapping アノテーションは、インターフェイスが POST リクエストのみを受け入れることを示します。@RequestBody アノテーションは、リクエスト本文内の JSON 形式のデータが Employee オブジェクトにバインドされていることを示します。HttpServletRequest リクエストは HTTP リクエスト情報を表します。Employee オブジェクトは、従業員 ID、名前、性別、役職などの属性を含む従業員の情報を表します。
メソッド内で、log.info を使用して、新しく追加された従業員情報を出力します。次に、従業員オブジェクトに対していくつかの前処理操作が実行されます。
- 初期パスワード 123456 を設定し、MD5 で暗号化して従業員オブジェクトに保存します。
- 現在の時刻を取得し、それぞれ作成時刻と更新時刻として設定します。
- 現在ログインしているユーザーの ID をセッションから取得し、それをユーザー作成および更新ユーザーとして設定します。
最後に、employeeService.save() メソッドを呼び出して従業員情報をデータベースに書き込み、インターフェイスが戻ったときにカスタム応答クラス R を返します。ここで、success は成功のステータスを示し、「新しい従業員が成功しました」はその内容を示します。応答メッセージ。
つまり、このコードの主な機能は、クライアントから送信された従業員情報を受信してデータベースに書き込み、いくつかの前処理操作を実行することです。同時にログを記録し、応答結果を返します。
新入社員のテスト
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-TLxlqAru-1688460908067)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131535557.png)]
zhagsan に入ると問題が発生します
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-sYFBDM4l-1688460908070)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131535685.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-oakWy0Xb-1688460908072)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306052104630.png)]
2.5 機能テスト
コードを記述したら、プロジェクトを再起動する必要があります。完了後、管理システムのホームページに直接アクセスし、「従業員管理」ページの「従業員を追加」ボタンをクリックして、従業員の基本情報を入力し、 「保存」をクリックしてデータを保存し、保存後、従業員データがデータベースに入力されているかを確認します。
テストにユーザーを追加し、既存のユーザー名を入力すると、フロントエンド インターフェイスにエラー メッセージが表示されます。
現時点では、サーバーからエラーが報告されており、エラー メッセージは次のとおりです。
上記のエラーは主に、従業員テーブル構造でユーザー名フィールドに一意のインデックスを確立していることが原因で発生します。重複するユーザー名データを追加するときに制約に違反すると、エラーが報告されます。しかし現時点では、フロントエンドから要求される情報は具体的ではなく、ユーザーには例外の原因がわからないため、詳細なエラー情報をユーザーに要求する必要があります。
2.6 グローバル例外処理
2.6.1 アイデア分析
上記のテストの問題を解決するには、プログラム内で発生する可能性のある例外をキャプチャする必要がありますが、通常、これらに対処するには次の 2 つの方法があります。
A. 例外をキャプチャするために、コントローラー メソッドに try...catch を追加します。
形式は次のとおりです。
この方法を使えば解決できるものの、他の業務データを保存する際にもControllerのメソッドにtry...catchを追加して処理する必要があり、コードが冗長で汎用的ではないというデメリットもあります。
B. グローバル例外キャプチャに例外ハンドラーを使用する
この方法では、プロジェクト内で一般的なグローバル例外ハンドラーを定義するだけで、このプロジェクト内のすべての例外を解決できます。
2.6.2 グローバル例外ハンドラ
プロジェクト内のグローバル例外ハンドラーをカスタマイズし、例外ハンドラーに注釈 @ControllerAdvice を追加し、属性注釈を通じてインターセプトするコントローラー メソッドのタイプを指定します。また、例外ハンドラーのメソッドに @ExceptionHandler アノテーションを追加して、どのタイプの例外をインターセプトするかを指定します。
例外処理メソッドのロジック:
- キャッチされた例外タイプを SQLIntegrityConstraintViolationException として指定します
- 例外プロンプト情報を解析し、一意性制約に違反する値を取得します。
- エラーメッセージを組み立てて返す
/**
* 全局异常处理
*/
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
/**
* 异常处理方法
* @return
*/
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){
log.error(ex.getMessage());
return R.error("失败了");
}
}
コードの説明 1:
上記のコードは、グローバル例外処理のクラスです。このクラスは、Spring の @ControllerAdvice アノテーションを使用して、グローバル例外ハンドラーとして識別します。このアノテーションを通じて、@RestController アノテーションおよび @Controller アノテーションが付けられたクラスで発生する例外をインターセプトします。
具体的な説明は以下の通りです。
@ControllerAdvice(annotations = {RestController.class, Controller.class})
: これは、グローバル例外処理クラスによってインターセプトされるコントローラー クラスのアノテーション タイプを指定するために使用されるクラス レベルのアノテーションです。ここでは、インターセプトするクラスが @RestController または @Controller アノテーションでマークされたクラスである必要があることを指定します。@ResponseBody
: これはメソッド レベルのアノテーションで、このメソッドの戻り値が、ビュー リゾルバーによってビューに解析されるのではなく、応答のコンテンツとしてクライアントに直接返されることを示します。ここでは、例外処理メソッドの戻り値が応答の JSON 形式に変換されるようにします。@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
: これは、メソッドによって処理される特定の例外タイプを指定するメソッド レベルのアノテーションです。ここでは、メソッドによって処理される例外が SQLIntegrityConstraintViolationException であることを指定します。public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex)
: これは、キャッチされた例外オブジェクトを表す SQLIntegrityConstraintViolationException 型のパラメーターを受け取る例外処理メソッドです。メソッドの戻り値の型は R で、R は応答データをラップするために使用されるカスタムの汎用応答オブジェクトです。log.error(ex.getMessage())
: このコード行は、Slf4j が提供するログ機能を使用して、異常なエラー メッセージをログに記録します。return R.error("失败了")
: このコード行は、例外処理後の応答結果を表す R オブジェクトを返します。R.error 静的メソッドを使用して、error 型の R オブジェクトを作成し、エラー メッセージを「失敗」に設定します。
要約すると、上記のコードは、コントローラー層で発生する SQLIntegrityConstraintViolationException 例外をキャプチャして処理し、ログにエラー情報を記録し、最終的に間違ったタイプの応答結果を返すために使用されるグローバル例外処理クラスを定義します。
コード解説2
このコードは、SpringBoot フレームワークに基づくグローバル例外処理クラスであり、SQL 例外をキャッチして処理するために使用されます。
@ControllerAdvice アノテーションは、このクラスがグローバル例外処理に使用されることを示します。インターセプトする必要があるコントローラーの注釈タイプは、注釈パラメーターを通じて @RestController および @Controller として指定されます。@ResponseBody アノテーションは、返されるデータが JSON 形式であることを示します。@Slf4j アノテーションは、ログを記録するためにログを使用することを示します。
@ExceptionHandler 注釈は、このメソッドが SQLIntegrityConstraintViolationException 型の例外をキャッチするために使用されることを示します。システムで SQLIntegrityConstraintViolationException タイプの例外が発生すると、例外処理のためにこのメソッドが呼び出されます。メソッド内で、log.error を使用して例外情報を出力し、カスタム応答クラス R を返します。ここで、error は失敗のステータスを示し、「failed」は応答メッセージの内容を示します。
つまり、このコードの主な機能は、SQLIntegrityConstraintViolationException タイプの例外の統合キャプチャと処理を実現することです。システム内でこの種の例外が発生した場合、このメソッドが実行されて例外を処理し、ログを記録し、応答結果を返します。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-oGQEzmmS-1688460908073)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131536773.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-zDnZxiTx-1688460908074)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131536460.png)]
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-m2WjK5TB-1688460908076)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131536013.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-gT3qFPmr-1688460908076)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131536837.png)]
パッケージ: com.iheima.reggie.common
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.sql.SQLIntegrityConstraintViolationException;
/**
* 全局异常处理
*/
@ControllerAdvice(annotations = {
RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
/**
* 异常处理方法
* @return
*/
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){
log.error(ex.getMessage());
if(ex.getMessage().contains("Duplicate entry")){
String[] split = ex.getMessage().split(" ");
String msg = split[2] + "已存在";
return R.error(msg);
}
return R.error("未知错误");
}
}
ノート:
上記のグローバル例外ハンドラーで使用される 2 つのアノテーション @ControllerAdvice と @ResponseBody は次のとおりです。
@ControllerAdvice : インターセプトするコントローラーのタイプを指定します。
@ResponseBody: メソッドの戻り値Rオブジェクトをjson形式のデータに変換し、ページに応答します。
上記で使用した 2 つのアノテーションを 1 つのアノテーションに結合することもできます @RestControllerAdvice
コード説明1
上記のコードは、 という名前の例外処理クラスを含む Java クラスですGlobalExceptionHandler
。このクラスには、例外のタイプをパラメータとしてexceptionHandler
受け取る という名前のメソッドが含まれています。SQLIntegrityConstraintViolationException
exceptionHandler
このメソッドでは、まずlog.error(ex.getMessage())
例外メッセージをログに保存するメソッドを使用します。次に、ex.getMessage()
メソッドを使用して例外メッセージを取得し、それを複数の文字列に分割してさらに処理します。
例外メッセージに string が含まれている場合"Duplicate entry"
、メソッドはsplit()
メソッドを使用して文字列を複数の文字列に分割し、そこから 3 番目の文字列を取得します。これは通常、重複の存在を説明する詳細です。最後に、メソッドはerror()
メソッドを使用して詳細をR<String>
type の応答に変換し、その応答を返します。例外メッセージに他の文字列が含まれている場合、メソッドはR.error("未知错误")
type の応答を返します。
@ExceptionHandler
このコードの注釈は、処理される例外のタイプを指定し、R<String>
データのタイプを返すために使用されることに注意してください。このアノテーションは、@RestController
例外処理を RESTful API と統合するためにアノテーションとともに使用する必要があります。
詳しく説明する
上記のコードのアノテーション@ExceptionHandler
は例外処理アノテーションであり、どのタイプの例外を処理するかを指定するために使用されます。この例では、@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
メソッドは、SQLIntegrityConstraintViolationException
次のタイプの例外を処理するように指定されています。
@ExceptionHandler
アノテーションは、処理する例外のタイプである 1 つのパラメータを取ります。この例では、SQLIntegrityConstraintViolationException
は処理する例外タイプです。exceptionHandler
プログラムでこのような例外が発生すると、処理のためにメソッドに渡されます。
exceptionHandler
SQLIntegrityConstraintViolationException
メソッドとは、例外の種類をパラメータとして受け取る戻り値メソッドです。メソッド内では、まずlog.error(ex.getMessage())
メソッドを使用して例外メッセージをログに保存します。次に、ex.getMessage()
メソッドを使用して例外メッセージを取得し、それを複数の文字列に分割します。
例外メッセージに string が含まれている場合"Duplicate entry"
、メソッドはsplit()
メソッドを使用して文字列を複数の文字列に分割し、そこから 3 番目の文字列を取得します。これは通常、重複の存在を説明する詳細です。error()
この例では、3 番目の文字列をパラメータとしてメソッドに渡し、詳細をR<String>
型指定された応答に変換します。例外メッセージに他の文字列が含まれている場合、メソッドはR.error("未知错误")
type の応答を返します。
最後に、例外処理を RESTful API と統合する必要があります。この例では、@RestController
アノテーションは、コントローラーが RESTful API リクエストを処理することを指定します。したがって、プログラムで例外が発生すると、その例外は RESTful API コントローラーの例外処理関数に渡されます。この場合、関数は@ExceptionHandler
アノテーションを使用して処理する例外のタイプを指定し、エラー応答を返します。
コード解説2
上記のコードはグローバル例外ハンドラーであり、@RestController または @Controller でマークされたコントローラーでスローされた例外をキャッチし、統一された形式でエラー メッセージを返すために使用されます。
このうち、@ControllerAdvice アノテーションはこのクラスがグローバル例外ハンドラーであることを示し、@ResponseBody アノテーションは返される結果が JSON 形式のデータであることを示し、@Slf4j はログ情報の出力によく使用される Slf4j ロギング ツールです。
コードの実装に関しては、@ExceptionHandler アノテーションを使用して、処理される例外のタイプを指定し、タイプ R のデータを返します。
このコードの処理の流れは、SQLIntegrityConstraintViolationExceptionの例外をキャッチした際、例外情報に「重複エントリ」という文字が含まれている場合はデータ重複の例外とみなし、例外情報から特定のデータを抽出し、その場合、その情報を含むメッセージが R 型のデータとして返され、それ以外の場合は R 型の「不明なエラー」データが返されます。
コード解説3
上記のコードは、Spring フレームワークによって提供される @ControllerAdvice アノテーションを使用するグローバル例外処理クラスです。このクラスは、コントローラーでスローされた例外をキャッチして処理するために使用されます。
コード内の注釈は、@ControllerAdvice(annotations = {RestController.class, Controller.class})
クラスが@RestController
または の@Controller
注釈が付けられたコントローラで発生する例外のみを処理することを示します。
注釈は@ResponseBody
、このクラスのメソッドによって返される結果が、ビュー リゾルバーによってビューとして解析されるのではなく、応答本文として直接返されることを示します。javabeenをJSONに変換して返すことです
@Slf4j
ロガーを自動生成するための Lombok アノテーションです。
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
メソッドがSQLIntegrityConstraintViolationException
タイプの例外を処理することを示します。このメソッドでは、まず例外のエラー メッセージを記録し、次にエラー メッセージに「重複エントリ」が含まれているかどうかを確認し、含まれている場合はエラー メッセージの内容に従って対応するエラー メッセージを生成し、オブジェクト (おそらくR
カスタム応答オブジェクト)。
エラー メッセージに「重複エントリ」が含まれていない場合は、デフォルトのエラー メッセージを含むオブジェクトが返されますR
。
コード内のこのコード行は返回 R.error(msg);
擬似コードであり、実際にはR
オブジェクトを返す必要があることに注意してください。この場合、疑似コードは、エラーメッセージR.error(msg)
を含むオブジェクトを返すことを意味します。具体的なオブジェクトの実装や利用方法は、実際の状況に応じて定義し、処理する必要があります。msg
R
R
概要: 上記のコードは、コントローラーでスローされた例外をキャッチして処理するためのグローバル例外処理クラスですSQLIntegrityConstraintViolationException
。例外のエラーメッセージに応じて、対応するエラーメッセージを生成し、R
例外処理結果を表すオブジェクト(擬似コード)を返します。
詳しく説明する
Spring フレームワークを使用して開発する場合、より適切なエラー処理とフレンドリーなエラー応答を提供するために、コントローラーでスローされる可能性のある例外を処理する必要があることがよくあります。この目的には、グローバル例外処理クラスが使用されます。
まず、@ControllerAdvice
アノテーションを使用して、クラスをグローバル例外処理クラスとして識別できます。この例では、アノテーションは、およびannotations
として処理する必要があるコントローラー アノテーションのタイプを指定する属性を使用します。@RestController
@Controller
次に、@ExceptionHandler
アノテーションを使用してメソッドを例外ハンドラーとして識別します。この場合、メソッドはSQLIntegrityConstraintViolationException
タイプ の例外を処理します。
例外処理メソッドでは、まず@Slf4j
アノテーションを使用して、例外のエラー メッセージを記録するロガーを生成します。
次に、例外のエラーメッセージに「重複エントリ」が含まれているかどうか、つまり一意性制約違反(重複エントリ)によってスローされた例外であるかどうかを確認します。その場合、エラー メッセージから対応する情報を抽出し、その情報に基づいて新しいエラー メッセージを生成します。
この例では、 を使用してex.getMessage().contains("Duplicate entry")
エラー メッセージに「重複エントリ」が含まれているかどうかを確認し、 を使用してex.getMessage().split(" ")
エラー メッセージをスペースで分割して関連情報を取得します。
新しいエラー メッセージを生成した後、エラー メッセージR.error(msg)
を含む応答オブジェクトを作成します。msg
以下はR.error()
、エラー メッセージを含む応答オブジェクトを返す疑似コードです。
エラー メッセージに「重複エントリ」が含まれていない場合は、他の不明なエラーを意味し、不明なエラーを示すデフォルトのエラー メッセージを含むデフォルトのエラー応答オブジェクトを返します。
返回 R.error(msg);
コード内のこのコード行は疑似コードであり、実際にはオブジェクトを返す必要がありR
、実際の状況に応じて特定の戻りメソッドを定義して処理する必要があることに注意してください。
このグローバル例外処理クラスを使用すると、コントローラーでスローされた指定された種類の例外を一元的に処理し、カスタム エラー応答を提供できます。これにより、コード ロジックが簡素化され、統合された例外処理メカニズムが提供され、システムの堅牢性とユーザー エクスペリエンスが向上します。
既存の値を追加する場合
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-yYdGR7gY-1688460908077)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131537709.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-LPG10VAA-1688460908078)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131537244.png)]
存在しない値を追加する場合
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-ZxaVZMON-1688460908079)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131537941.png)]
2.6.3 テスト
グローバル例外ハンドラーを作成した後、プロジェクトを再起動し、管理システムのホームページに直接アクセスして、「従業員管理」ページの「従業員の追加」ボタンをクリックする必要があります。テストにユーザーを追加し、既存のユーザー名を入力すると、フロントエンド インターフェイスに次のエラー メッセージが表示されます。
3. 従業員ページのクエリ
3.1 需要分析
システム内の従業員数が多い場合、すべての従業員を1ページに表示するとごちゃごちゃして見にくくなるため、一般的なシステムでは一覧データをページ単位で表示します。やり方。ページネーションクエリページでは、ページネーション条件に加えて、クエリ「従業員名」などのクエリ条件もあります。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-Dgn6vaVn-1688460908081)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304021803131.png)]
-
リクエストパラメータ
-
検索条件:従業員名(あいまい検索)
-
ページネーション条件:各ページに表示する項目数、ページ番号
-
-
応答データ
- 合計
-
結果リスト
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-gbQrUaTx-1688460908082)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131538518.png)]
1). ページは ajax リクエストを送信し、ページネーション クエリ パラメーター (page、pageSize、name) をサーバーに送信します。
F12 ページを更新
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-kXxtcVB6-1688460908083) (C:\Users\zyz\AppData\Roaming\Typora) \typora-user-images\ image-20230605221909418.png)]
page=1&pageSize=10 最初のページを確認し、合計10個のデータを確認します
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-p1zw7eSO-1688460908084)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131538788.png)]
フロントエンドのコードを見てみる
リクエストがロードされるとすぐに送信されるのはなぜですか?
<script>
new Vue({
el: '#member-app',
data() {
return {
input: '',
counts: 0,
page: 1,
pageSize: 2,
tableData : [],
id : '',
status : '',
}
},
computed: {},
created() {
this.init()
if(localStorage.getItem('userInfo') != null){
//获取当前登录员工的账号,并赋值给模型数据user
this.user = JSON.parse(localStorage.getItem('userInfo')).username
}
},
mounted() {
},
methods: {
async init () {
const params = {
page: this.page,
pageSize: this.pageSize,
name: this.input ? this.input : undefined
}
await getMemberList(params).then(res => {
if (String(res.code) === '1') {
this.tableData = res.data.records || []
this.counts = res.data.total
}
}).catch(err => {
this.$message.error('请求出错了:' + err)
})
},
handleQuery() {
this.page = 1;
this.init();
},
// 添加
addMemberHandle (st) {
if (st === 'add'){
window.parent.menuHandle({
id: '2',
url: '/backend/page/member/add.html',
name: '添加员工'
},true)
} else {
window.parent.menuHandle({
id: '2',
url: '/backend/page/member/add.html?id='+st,
name: '修改员工'
},true)
}
},
//状态修改
statusHandle (row) {
this.id = row.id
this.status = row.status
this.$confirm('确认调整该账号的状态?', '提示', {
'confirmButtonText': '确定',
'cancelButtonText': '取消',
'type': 'warning'
}).then(() => {
enableOrDisableEmployee({ 'id': this.id, 'status': !this.status ? 1 : 0 }).then(res => {
console.log('enableOrDisableEmployee',res)
if (String(res.code) === '1') {
this.$message.success('账号状态更改成功!')
this.handleQuery()
}
}).catch(err => {
this.$message.error('请求出错了:' + err)
})
})
},
handleSizeChange (val) {
this.pageSize = val
this.init()
},
handleCurrentChange (val) {
this.page = val
this.init()
}
}
})
</script>
上記のコードは、Vue フレームワークを使用して記述されたフロントエンド ページ スクリプトです。いくつかのデータとメソッドを含む Vue インスタンスを作成します。
まず、 (入力ボックスの値)、(データの総数)、(現在のページ番号)、(各ページに表示されるデータの量)などのいくつかのデータがVue インスタンスのdata
プロパティで定義されます。 (テーブルデータ)、(従業員ID)、(従業員ステータス)など。input
counts
page
pageSize
tableData
id
status
created
ライフサイクルフック関数では、ブラウザのローカルストレージ(localStorage)を読み込んで、userInfo
現在ログインしている従業員のアカウント番号をデータに割り当てます。user
ライフ サイクル フック関数ではmounted
、ページのロード後に実行する必要があるいくつかの操作を実行できますが、このコード スニペットには特定のロジックはありません。
次にいくつかのメソッドの定義を示します。
init
メソッド: このメソッドはページ データを初期化するために使用され、getMemberList
関数を呼び出して従業員リスト データを取得し、返されたデータを と に代入しtableData
ますcounts
。handleQuery
メソッド: ユーザーがクエリ ボタンをクリックすると、page
ページ番号 ( ) が 1 にリセットされ、init
メソッドを呼び出してデータを再読み込みします。addMemberHandle
メソッド: 従業員の追加または変更の操作を処理するために使用されます。st
受信パラメータ(「追加」または従業員 ID の可能性があります)に従って、window.parent.menuHandle
メソッドを呼び出して対応するページを開き、従業員を追加または変更します。statusHandle
メソッド: アカウント状態の変更を処理するために使用されます。id
まず、とに従業員のIDとステータスを割り当てstatus
、確認ダイアログボックスを表示し、アカウントステータスの調整を確認した後、enableOrDisableEmployee
従業員のステータス変更リクエストを送信する関数を呼び出します。リクエストが成功すると、成功メッセージが表示され、handleQuery
メソッドが呼び出されてデータがリロードされます。handleSizeChange
メソッド: ユーザーが各ページに表示されるデータ量を変更する場合、新しいデータ量を に割り当てpageSize
、init
メソッドを呼び出してデータを再読み込みします。handleCurrentChange
メソッド: ユーザーが現在のページ番号を変更する場合、新しいページ番号を に割り当てpage
、init
メソッドを呼び出してデータを再ロードします。
要約すると、上記のコードは主に従業員管理のためのフロントエンド ページを実装しており、従業員リストの表示、クエリ、追加、変更、アカウント ステータスの変更などの機能が含まれます。
function getMemberList (params) {
return $axios({
url: '/employee/page',
method: 'get',
params
})
}
上記のコードは、getMemberList
という名前のパラメータを受け取る という名前の関数を定義しますparams
。
この関数は、$axios
オブジェクト (おそらく Ajax リクエストをカプセル化するライブラリ) を使用して、リクエストされた URL に GET リクエストを送信します/employee/page
。リクエストのパラメータはparams
オブジェクトを使用して渡され、リクエストのメソッドは GET に設定されます。
関数が実行されると、 Promise オブジェクトが返され、リクエストの結果またはエラーは.then()
メソッドを通じて処理できます.catch()
。
params
つまり、この関数は指定された URL に GET リクエストを送信するために使用され、パラメータは従業員リストのデータを取得するためのオブジェクト内のパラメータです。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-d7wxrkJk-1688460908085)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131538116.png)]
3.2 プログラム実行の流れ
3.2.1 ページフロー分析
コードを開発する前に、プログラム全体の実行プロセスを整理する必要があります。
A. メニューをクリックして従業員管理ページを開き、次のクエリを実行します。
B. 検索バーに従業員の名前を入力し、Enter キーを押して、クエリを実行します。
1). ページは ajax リクエストを送信し、ページネーション クエリ パラメーター (page、pageSize、name) をサーバーに送信します。
2). サーバー コントローラーはページによって送信されたデータを受信し、サービスを呼び出してデータをクエリするための条件を組み立てます。
3). サービスは Mapper を呼び出してデータベースを操作し、ページングされたデータをクエリします
4). コントローラーは、フロントエンド ページにクエリされたページ データに応答します。
5). ページはページ データを受信し、ElementUI の Table コンポーネントを通じてページ上に表示します。
3.2.2 フロントエンドコードの紹介
1). 従業員リストページ /member/list.html にアクセスすると、Vuejs のフックメソッドがトリガーされ、ページの初期化時に作成されたメソッドが呼び出されます。
上記のフロントエンド コードから、ページネーション クエリの実行後、フロントエンドに返す必要がある情報には、レコードにカプセル化された結果のリストとカプセル化されたレコードの総数の 2 つの項目が含まれている必要があることがわかります。合計で。
リクエスト パラメータを組み立てるとき、page と pageSize はフロントエンド ページング プラグインがレンダリングするときのパラメータです。
2). getMemberList メソッドで、axios を介して非同期リクエストを開始します。
axios によって開始された非同期リクエストは、request.js で宣言されたリクエスト インターセプターによってインターセプトされ、そこで get リクエストがさらにパッケージ化されて処理されます。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-sBOP16Mi-1688460908087)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304021804051.png)]
サーバーに送信される最終リクエストは次のとおりです: GET リクエスト、リクエスト リンク /employee/page?page=1&pageSize=10&name=xxx
3.3 コードの実装
3.3.1 ページングプラグインの設定
現在ページングクエリ機能を実装したいのですが、MybatisPlusでページング機能を実装するにはMybatisPlusが提供するページングプラグインを使用する必要があり、ページングプラグインを使用するにはページングプラグインのBeanオブジェクトを宣言する必要があります。構成クラスの -in。
所属パッケージ:com.iheima.reggie.config
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 配置MP的分页插件
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//创建了一个`MybatisPlusInterceptor`对象
//`MybatisPlusInterceptor`是MyBatis-Plus框架提供的拦截器,可以在执行MyBatis的SQL语句过程中添加额外的功能。
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//通过调用`addInnerInterceptor`方法,将一个`PaginationInnerInterceptor`对象作为内部拦截器添加到`MybatisPlusInterceptor`中。`PaginationInnerInterceptor`是MyBatis-Plus提供的分页插件,它能够拦截SQL语句,并根据传入的分页参数自动进行分页查询。
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
コード説明1
上記のコードは、MyBatis-Plus (略して MP) のページング プラグインを構成するために使用される Java クラスです。
@Configuration
注釈は、これがアプリケーションの一部のコンポーネントまたは機能を構成するために使用される構成クラスであることを示します。MybatisPlusConfig
名前付き Bean メソッドがクラス内に定義され、オブジェクトmybatisPlusInterceptor
を作成して返しますMybatisPlusInterceptor
。MybatisPlusInterceptor
MyBatis-Plus が提供するインターセプタで、MyBatis の SQL 実行処理をインターセプトし、実行処理中に機能を追加するために使用されます。メソッドを呼び出して、オブジェクトを内部インターセプターとしてaddInnerInterceptor
追加します。PaginationInnerInterceptor
MybatisPlusInterceptor
PaginationInnerInterceptor
これは MyBatis-Plus が提供するページング プラグインで、SQL ステートメントを自動的にインターセプトし、受信ページング パラメーターに従ってページング クエリを実行できます。PaginationInnerInterceptor
に追加するとMybatisPlusInterceptor
、クエリ結果の自動ページネーションを実現できます。@Bean
アノテーションは、メソッドによって返されたオブジェクトが Spring Bean として登録され、依存関係注入を通じて他のコンポーネントで使用できることを示します。
要約すると、上記のコードは MyBatis-Plus のページング プラグインを構成し、MybatisPlusInterceptor
オブジェクトを作成して内部インターセプターとして追加することでPaginationInnerInterceptor
MyBatis の自動ページング機能を実現します。
もっと詳しく
データベース操作に MyBatis-Plus フレームワークを使用する場合、クエリ結果をページに表示する必要がある場合があります。上記のコードは、MyBatis-Plus のページング プラグインを設定する方法を示しています。
まず、Java クラスを作成し、@Configuration
これが構成クラスであることを示すアノテーションを追加します。このクラスの主な目的は、MyBatis-Plus のページング プラグインを設定することです。
この構成クラスでは、mybatisPlusInterceptor
という名前のメソッドが定義され、@Bean
アノテーションが付けられています。これは、このメソッドによって返されたオブジェクトが Spring Bean として登録され、依存関係注入を通じて他のコンポーネントで使用できることを意味します。
このメソッドではmybatisPlusInterceptor
、オブジェクトが作成MybatisPlusInterceptor
および構成されます。MybatisPlusInterceptor
これは、MyBatis-Plus フレームワークによって提供されるインターセプターであり、MyBatis SQL ステートメントの実行中に追加の関数を追加できます。
メソッドを呼び出して、オブジェクトを内部インターセプタとしてaddInnerInterceptor
追加します。これは MyBatis-Plus が提供するページング プラグインで、SQL ステートメントをインターセプトし、受信したページング パラメーターに従ってページング クエリを自動的に実行できます。PaginationInnerInterceptor
MybatisPlusInterceptor
PaginationInnerInterceptor
このようにして、MyBatis の自動ページング機能は、設定されたMybatisPlusInterceptor
内部インターセプターを通じて実現されます。PaginationInnerInterceptor
要約すると、上記のコードは MyBatis-Plus のページング プラグインを構成し、データベース クエリに MyBatis-Plus を使用するときにページング操作を便利に実行できるようにし、クエリ結果をページ上にバッチで表示できるようにします。 。このようにして、開発者はページング ロジックを手動で記述する必要がなく、ページング プラグインが自動的に SQL ステートメントをインターセプトし、受信ページング パラメーターに従ってページング クエリを実行できるため、開発プロセスが簡素化されます。
コード解説2
このコードは、MyBatis Plus ページネーション プラグインの構成を実装します。MyBatis Plus は MyBatis をベースにした拡張ツールで、開発効率を向上させながらいくつかの強力な機能を提供します。その 1 つがページネーション プラグインです。
このコードでは、MybatisPlusInterceptor インスタンスを定義し、それにページング関数の実装に使用される PaginationInnerInterceptor 内部インターセプターを追加します。最後に、MybatisPlusInterceptor インスタンスを Spring コンテナに Bean として登録して、MyBatis Plus ページング プラグインの構成を完了します。
コード解説3
上記のコードは、名前付き Bean を定義する MyBatis-Plus の構成クラスですmybatisPlusInterceptor
。この Bean の役割は、MyBatis-Plus のページネーション プラグインをページネーション処理に使用することです。
このメソッドではmybatisPlusInterceptor
、 という新しいオブジェクトを作成しMybatisPlusInterceptor
、それを返します。このオブジェクトは、SQL 操作の実行前または実行後にインターセプトできるインターセプター オブジェクトです。PaginationInnerInterceptor
ここでは、クエリ操作の実行時にページネーション用の内部インターセプターを追加します。
PaginationInnerInterceptor
カスタム内部インターセプタであり、その機能はクエリ操作を実行する際にクエリ文を複数の部分に分割し、必要に応じて各部分に対してページング処理を実行することです。この例では、各部分のサイズを 10 に設定します。これは、各部分のサイズが 10 レコードであることを意味します。
MybatisPlusInterceptor
オブジェクトを返した後、構成ファイルでメソッドを定義して@Bean
オブジェクトを作成できます。この場合、クラスはオブジェクトを作成するメソッドMybatisPlusConfig
を定義する構成クラスです。@Bean
mybatisPlusInterceptor
MybatisPlusInterceptor
構成ファイルでオブジェクト@Bean
を作成するメソッドを定義することによりMybatisPlusInterceptor
、アプリケーションの起動時にクエリ実行時のページネーション用に MyBatis-Plus を自動的に構成できます。
もっと詳しく
MyBatis-Plus はオープンソースの永続層フレームワークであり、自動テーブル作成、動的 SQL、トランザクション管理などの多くの機能を提供します。中でもページネーションプラグインは、MyBatis-Plus が提供する重要な機能で、開発者がページネーション処理をより便利に行うのに役立ちます。
上記のコードのクラスは、オブジェクトを作成するメソッドMybatisPlusConfig
を定義する構成クラスです。このオブジェクトは、SQL 操作の実行前または実行後にインターセプトできるインターセプター オブジェクトです。ここでは、内部インターセプタを追加しました。その機能は、クエリ操作の実行時にクエリ ステートメントを複数の部分に分割し、必要に応じて各部分にページ付けすることです。@Bean
mybatisPlusInterceptor
MybatisPlusInterceptor
PaginationInnerInterceptor
PaginationInnerInterceptor
MyBatisPlusInterceptor
クラスを継承するカスタム内部インターセプターです。MyBatisPlusInterceptor
Class は MyBatis-Plus によって提供されるデフォルトのインターセプタ クラスであり、SQL フィルタリング、トランザクション管理、例外処理などのいくつかの基本的なインターセプト機能を提供します。PaginationInnerInterceptor
クラスでは、beforeQuery
クエリの前にページネーションを行うなど、これらのメソッドの一部をオーバーライドします。
beforeQuery
このメソッドでは、String.split()
メソッドを使用してクエリを部分に分割し、各部分をパラメータとして のメソッドに渡しMyBatisPlusInterceptor
ますbeforeQuery
。beforeQuery
このメソッドでは、MapperScannerConfigurer
クラスを使用して、クエリ時に対応する操作を実行するように Mapper インターフェイスをスキャンおよび構成できます。
上記のコードにより、MyBatis-Plus のソースコードを変更することなく、MyBatis-Plus にページング機能を実装できます。同時に、アプリケーションの起動時に MyBatis-Plus が自動的に設定されるように、オブジェクトを作成する@Bean
メソッドを設定ファイルに定義することもでき、それによってシステムの保守性と拡張性が向上します。MybatisPlusInterceptor
3.3.2 ページングクエリの実装
上記で分析したように、ページがページネーション クエリを実行するとき、具体的なリクエスト情報は次のとおりです。
聞く | 説明する |
---|---|
リクエストメソッド | 得る |
リクエストパス | /従業員/ページ |
リクエストパラメータ | ページ、ページサイズ、名前 |
では、クエリの完了後にフロントエンドにどのような結果を返す必要があるのでしょうか?
また、クエリによって返される結果データは 2 つの情報をカプセル化する必要があることも上記で分析しました。つまり、レコードはページング リスト データをカプセル化し、合計は条件を満たすレコードの総数をカプセル化します。このとき、コントローラーメソッドの戻り値の型 R を定義する際に、MybatisPlus ページ分割クエリの結果 Page を直接カプセル化して返すことができます。これは、Page 内のプロパティが次のとおりであるためです。
次に、これらの既知の要件と条件に基づいて、ページネーション クエリのコード実装が完了します。具体的なロジックは次のとおりです。
A. ページネーション条件を構築する
B. 検索条件の作成 - あいまい一致の名前
C. ソート条件の構築 - 更新時刻の逆順にソートする
D. クエリを実行する
E. 結果をアセンブルして返す
records 结果列表
total 总记录数
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-CXUtqRG7-1688460908088)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131539429.png)]
サーバーからの応答を受信する
await getMemberList(params).then(res => {
if (String(res.code) === '1') {
this.tableData = res.data.records || []
this.counts = res.data.total
}
}
サーバーから返されたデータ
this.tableData = res.data.records || []
this.counts = res.data.total
これは、応答する JSON にはレコード合計フィールドが必要ですが、従業員にはこれら 2 つのフィールドがないことを意味します。したがって、EmployeeController で使用するジェネリック タイプは Page である必要があります。 Page は、MybatisPlus によってカプセル化されたクラスです。ページング クエリを実行します。以下に示すように、このオブジェクトも返されます。
Page には、.records 属性と total 属性があります。Records は、現在のページに表示されるリスト データ、レコードの合計数、およびレコードの合計数です。ここで Page を使用する理由は、データ レコードとページには合計が必要です。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-hzsRlDjw-1688460908089)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131539517.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-7cVWiVjr-1688460908090)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131540157.png)]
public R<Page> page() {
return null;
}
/**
* 员工信息分页查询
* @param page 当前查询页码
* @param pageSize 每页展示记录数
* @param name 员工姓名 - 可选参数
* @return
*/
@GetMapping("/page")
public R<Page> page(int page ,int pageSize, String name) {
log.info("page = {},pageSize = {},name = {}" ,page,pageSize,name);
return null;
}
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-jryzYHDC-1688460908091)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131540813.png)]
ページを更新してログインします
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-lgQ7Anmi-1688460908092)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131540365.png)]
F8
手放す
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-3yuxSMuq-1688460908092)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131540621.png)]
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-Nvr0TdpU-1688460908093)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131540085.png)]
具体的なコードの実装は次のとおりです。
/**
* 员工信息分页查询
* @param page 当前查询页码
* @param pageSize 每页展示记录数
* @param name 员工姓名 - 可选参数
* @return
*/
@GetMapping("/page")
public R<Page> page(int page,int pageSize,String name){
log.info("page = {},pageSize = {},name = {}" ,page,pageSize,name);
//构造分页构造器
Page pageInfo = new Page(page,pageSize);
//构造条件构造器
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper();
//添加过滤条件
queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);
//添加排序条件
queryWrapper.orderByDesc(Employee::getUpdateTime);
//执行查询
employeeService.page(pageInfo,queryWrapper);
return R.success(pageInfo);
}
コード説明1
上記のコードは、Java Spring Boot での従業員情報ページング クエリのインターフェイス メソッドです。コードの説明は次のとおりです。
@GetMapping("/page")
: これは、ページネーション クエリ リクエストを処理するために使用される GET リクエストのマッピング パスです。リクエストのパスは です/page
。public R<Page> page(int page, int pageSize, String name)
: これは戻り値の型が のパブリック メソッド、R<Page>
つまり応答結果をラップするオブジェクトです。メソッド名は、現在のクエリのページ番号、各ページに表示されるレコードの数、および従業員名 (オプションのパラメーター) のpage
3 つのパラメーターを受け入れます。page
pageSize
name
log.info("page = {},pageSize = {},name = {}", page, pageSize, name)
: このコード行は、ログを出力し、渡されたパラメーター値を記録するために使用されます。Page pageInfo = new Page(page, pageSize)
: これは、ページング オブジェクトの作成に使用されるページネーション コンストラクターで、現在のクエリのページ番号と各ページに表示されるレコードの数を渡します。LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper()
: これは条件コンストラクターであり、クエリ条件オブジェクトを構築するために使用されます。queryWrapper.like(StringUtils.isNotEmpty(name), Employee::getName, name)
: このコード行は、従業員名 (Employee
オブジェクト属性) に基づいてname
あいまい一致を実行するあいまいクエリ条件を追加します。パラメータが空でないかどうかをStringUtils.isNotEmpty(name)
判断し、空でない場合はあいまいクエリ条件を追加し、空でない場合は条件を追加しません。name
queryWrapper.orderByDesc(Employee::getUpdateTime)
: このコード行は、従業員の更新時間 (Employee
オブジェクト のupdateTime
プロパティ) に基づいて降順で並べ替える並べ替え条件を追加します。employeeService.page(pageInfo, queryWrapper)
: このコード行は、クエリ操作を実行し、メソッドを呼び出しemployeeService
、page
ページング オブジェクトとクエリ条件オブジェクトを渡し、クエリ結果をpageInfo
オブジェクトにカプセル化します。return R.success(pageInfo)
: 最後に、クエリ結果をカプセル化したオブジェクトがpageInfo
応答結果として使用され、R.success()
メソッドによってラップされた後に返されます。
一般に、このインターフェイス メソッドはページネーション クエリのパラメータを受け取り、パラメータに従ってクエリ条件を構築し、クエリ操作を実行して、クエリ結果を含むページング オブジェクトを返します。
この中の StringUtils とは何ですか
StringUtils
文字列処理ツールのクラスで、通常は Apache Commons Lang ライブラリのクラスです。文字列が空かどうかの判断、文字列内のスペースの削除、文字列の比較など、文字列を処理するための多くのユーティリティ メソッドが提供されます。
コード内では、パラメータが空かどうかをStringUtils.isNotEmpty(name)
判断するために使用されます。空でないname
場合は戻り、空または nullの場合は戻ります。この判定条件は、問合せ条件に従業員名のあいまい問合せ条件を追加するかどうかを決定するために使用されます。name
true
name
false
StringUtils
クラスにはさまざまな実装を含めることができ、どの実装を使用するかは、プロジェクトに導入されたライブラリとバージョンによって異なることに注意してください。
コード解説2
上記のコードは、従業員情報のページング クエリのための単純な Spring Boot アプリケーションです。その機能は、現在のクエリのページ番号 page、各ページに表示されるレコード数、pageSize、従業員名という 3 つのパラメータを受け取り、成功した応答 PageInfo を返すことです。物体。
コードの詳細な説明は次のとおりです。
@GetMapping("/page")
アノテーションは、リクエスト パスが /page であることを指定し、これがpage
メソッドにマップされます。log.info("page = {},pageSize = {},name = {}" ,page,pageSize,name)
このメソッドでは、log.info
現在のクエリのページ番号 page、各ページに表示されるレコード数 pageSize、および従業員名の 3 つのパラメーターの値を出力するために使用されます。Page pageInfo = new Page(page,pageSize)
PageInfo オブジェクト pageInfo が作成され、ページング情報とクエリ条件をカプセル化するために使用されます。このうち、page
パラメータは現在のクエリのページ番号を指定し、pageSize
パラメータは各ページに表示されるレコードの数を指定します。LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper()
LambdaQueryWrapper オブジェクト queryWrapper が作成され、クエリ条件をカプセル化するために使用されます。その中には、Employee
従業員情報クラスのジェネリック型があり、name
パラメータにはクエリ対象の従業員の名前を指定します。queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name)
従業員名に対してあいまい一致を行うフィルターを追加しました。このうちStringUtils.isNotEmpty(name)
メソッドは、nameパラメータが空でないかどうかをチェックし、Employee::getName
従業員名を返すために使用される従業員情報のクラスメソッドgetNameを参照します。queryWrapper.orderByDesc(Employee::getUpdateTime)
従業員更新時刻の降順でソートするというソート条件を追加しました。employeeService.page(pageInfo,queryWrapper)
employeeService の page メソッドが呼び出され、pageInfo オブジェクトと LambdaQueryWrapper オブジェクトの 2 つのパラメータを受け取ります。pageInfo オブジェクトはページング情報とクエリ条件をカプセル化するために使用され、LambdaQueryWrapper オブジェクトはクエリ条件をカプセル化するために使用されます。return R.success(pageInfo)
成功した応答オブジェクト R が返されます。これには、ページング情報とクエリ結果が含まれます。
要約すると、上記のコードは単純な従業員情報ページング クエリ関数を実装し、現在のクエリ ページ番号 page、各ページに表示されるレコード数、pageSize、および従業員名という 3 つのパラメータを受け取り、成功の応答 PageInfo オブジェクトを返します。
コード解説3
上記のコードは、Java SpringBoot プロジェクトの従業員情報ページング クエリ API インターフェイスであり、主に指定された条件を満たす従業員のリストをクエリし、ページングで表示するために使用されます。具体的な説明は以下の通りです。
- @GetMapping(“/page”) アノテーションは、このインターフェイスが GET リクエストを処理し、/page のパス マッピングを登録することを示します。
- 3 つのパラメーター page、pageSize、および name はそれぞれ、現在のクエリのページ番号、各ページに表示されるレコードの数、および従業員名 (オプション) を表し、これらのパラメーターはインターフェイスのリクエスト パラメーターとして渡されます。
- Page pageInfo = new Page(page, pageSize) pageInfo オブジェクトに値を割り当てます。page は現在のページ番号、pageSize は各ページに表示されるレコードの数です。このコード行はページ コンストラクター オブジェクトを構築し、これら 2 つを渡します。パラメータを指定して、それに Give pageInfo を割り当てます。
- LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() SQL クエリ ステートメントを構築するための条件コンストラクターを構築します。
- queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name) queryWrapper に条件フィルターを追加します。name が空でない場合は、名前に name が含まれる従業員データをクエリします。このうち
Employee::getName
、 は、Employee エンティティ クラスの getName メソッドを使用してフィルタリング操作を実行することを意味します。 - queryWrapper.orderByDesc(Employee::getUpdateTime) queryWrapper に並べ替え条件を追加し、従業員を更新時刻に従って降順に並べ替えます。ここで、 は、
Employee::getUpdateTime
並べ替え操作に Employee エンティティ クラスの getUpdateTime メソッドを使用することを意味します。 - employeeService.page(pageInfo,queryWrapper) クエリを実行し、クエリ結果を pageInfo オブジェクトに保存し、最後に pageInfo を返します。
- 最後に、インターフェイスは、success メソッドを使用して pageInfo を応答本文にカプセル化し、R クラス オブジェクトを返します。R は、インターフェイス応答のデータやステータスなどの情報をカプセル化する一般的な応答クラスです。
3.4 機能テスト
コードを記述した後、プロジェクトを再起動する必要があります。完了後、管理システムのホームページに直接アクセスすると、デフォルトで従業員管理の一覧ページが開きます。一覧データが正常に表示されるかどうかを確認できます。 、またはページング プラグインを使用してページング機能をテストし、従業員名のファジー クエリ機能をテストします。
テスト時に、ブラウザーの監視ツールを使用して、ページとサーバー間のデータ対話の詳細を表示できます。そして、デバッグの助けを借りて、サーバーパラメーターの受信とロジックの実行に従ってください。
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-kgoO7taS-1688460908094)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202304021805171.png)]
テスト中に、従業員ステータス フィールド (ステータス) について、サーバーはステータス コード (1 または 0) を返しますが、ページには処理されたデータが表示されているため、ページには「通常」または「無効」が表示されることがわかります。 。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-RQTKX90k-1688460908095)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131541053.png)]
F8を2回
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-XIHfXtYv-1688460908095)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131541021.png)]
F8を3回
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-6kithCUS-1688460908096)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131541653.png)]
F8
==> Preparing: SELECT COUNT(*) FROM employee
==> Parameters:
<== Columns: COUNT(*)
<== Row: 4
<== Total: 1
==> Preparing: SELECT id,username,name,password,phone,sex,id_number,status,create_time,update_time,create_user,update_user FROM employee ORDER BY update_time DESC LIMIT ?
==> Parameters: 10(Long)
<== Columns: id, username, name, password, phone, sex, id_number, status, create_time, update_time, create_user, update_user
<== Row: 1665721390604546050, lisi, 李四, e10adc3949ba59abbe56e057f20f883e, 13528659545, 1, 358956221565220, 1, 2023-06-05 22:05:02, 2023-06-05 22:05:02, 1, 1
<== Row: 1665562193044803586, zhangsan, zs, e10adc3949ba59abbe56e057f20f883e, 13412345678, 1, 350689566956852556, 1, 2023-06-05 11:32:26, 2023-06-05 11:32:26, 1, 1
<== Row: 1665561007872905218, zhagsan, 张三, e10adc3949ba59abbe56e057f20f883e, 13412345678, 1, 350689566956852556, 1, 2023-06-05 11:27:44, 2023-06-05 11:27:44, 1, 1
<== Row: 1, admin, 管理员, e10adc3949ba59abbe56e057f20f883e, 13812312312, 1, 110101199001010047, 1, 2021-05-06 17:20:07, 2021-05-10 02:24:09, 1, 1
<== Total: 4
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-hbaplbux-1688460908097)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131541028.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-GTIWVIAb-1688460908097)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131541445.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-Dsma9Jn4-1688460908098)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131542324.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-3aifa4Pi-1688460908099)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131542565.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-pB8Y46cJ-1688460908100)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131542584.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-9PS8Gm5r-1688460908100)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131542621.png)]
4. 従業員アカウントの有効化/無効化
4.1 需要分析
従業員管理リスト ページでは、従業員アカウントを有効または無効にすることができます。アカウントが無効になっている従業員はシステムにログインできませんが、アカウントが有効になっている従業員は通常どおりログインできます。従業員アカウントの状態が正常であればボタンは「無効」、従業員アカウントの状態が無効であればボタンは「有効」と表示されます。
なお、他の一般ユーザーの有効・無効を設定できるのは管理者(adminユーザー)のみであるため、一般ユーザーがシステムにログインした後は有効・無効ボタンは表示されません。
A. admin 管理者ログイン
B. 一般ユーザーのログイン
4.2 プログラム実行の流れ
4.2.1 ページボタンの動的表示
上記の要件で、達成する必要がある効果は、管理者 (管理者ユーザー) のみが他の一般ユーザーを有効化および無効化できるため、一般ユーザーがシステムにログインした後は、有効化および無効化のボタンが表示されないことであると述べました。ページにはどのように表示されますか? 管理者 admin のみが有効化ボタンと無効化ボタンを表示できるようにしますか?
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-QAWJruTQ-1688460908101)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131543430.png)]
1). リストページ(list.html)が読み込まれると、作成したフック関数が起動され、localStorageからユーザーのログイン情報を取得し、ユーザー名を取得します。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-wo8yecOq-1688460908101)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131543117.png)]
取得後、モデルデータをユーザーに渡します
モデルデータのユーザーを取得後、Vue コマンドの v-if で判定し、ログインユーザーが admin の場合は有効化/無効化ボタンが表示され、そうでない場合は表示されません。
</el-button>
<el-button
type="text"
size="small"
class="delBut non"
@click="statusHandle(scope.row)"
v-if="user === 'admin'" // 通过Vue指令v-if进行判断,如果登录用户为admin将展示 启用/禁用 按钮, 否则不展示
>
{
{ scope.row.status == '1' ? '禁用' : '启用' }}
</el-button>
2). ページ内で Vue コマンド v-if で判断し、ログインユーザーが admin の場合は有効化/無効化ボタンが表示され、それ以外の場合は表示されません。
4.2.2 実行プロセスの分析
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-6RBMtaOu-1688460908102)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131543885.png)]
1. ページは ajax リクエストを送信し、パラメーター (ID、ステータス) をサーバーに送信します。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-SLdGYm2y-1688460908102)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131543443.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-TASciZ0C-1688460908103)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131543717.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-rdDZUSZ8-1688460908103)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131544148.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-wkob9QrV-1688460908103)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131544276.png)]
2. サーバーコントローラーはページによって送信されたデータを受信し、サービスを呼び出してデータを更新します
3. サービスは Mapper を呼び出してデータベースを操作します
無効化または有効化ボタンをクリックするとリクエストが行われる理由
1). 管理者 admin が「有効」または「無効」ボタンをクリックすると、メソッド statusHandle が呼び出されます。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-mUTubERS-1688460908104)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131544669.png)]
scope.row : この行のデータ情報を取得します。
同時に、scope.row が送信されます。scope.row は、表示されるデータの完全にカプセル化された JSON オブジェクトです。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-pt04BjlQ-1688460908104)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131544852.png)]
2). statusHandle メソッドで 2 回目の確認を行った後、ajax リクエストを開始し、id および status パラメーターを渡します。
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-QBSqRSyF-1688460908105)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131544876.png)]
//状态修改
statusHandle (row) {
this.id = row.id //获得id的值
this.status = row.status //获得状态的值
this.$confirm('确认调整该账号的状态?', '提示', {
'confirmButtonText': '确定',
'cancelButtonText': '取消',
'type': 'warning'
}).then(() => {
enableOrDisableEmployee({ 'id': this.id, 'status': !this.status ? 1 : 0 }).then(res => {
console.log('enableOrDisableEmployee',res)
if (String(res.code) === '1') {
this.$message.success('账号状态更改成功!')
this.handleQuery()
}
}).catch(err => {
this.$message.error('请求出错了:' + err)
})
})
},
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-N3jZsQaM-1688460908105)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131545498.png)]
// 修改---启用禁用接口
function enableOrDisableEmployee (params) {
return $axios({
url: '/employee',
method: 'put',
data: { ...params }
})
}
最後に、サーバーを要求する非同期リクエストが開始されます。リクエスト情報は次のとおりです。
聞く | 説明する |
---|---|
リクエストメソッド | 置く |
リクエストパス | /職員 |
リクエストパラメータ | {「id」:xxx、「ステータス」:xxx} |
{…params} : Three dots は ES6 で登場したスプレッド演算子です。この機能は、現在使用されているオブジェクトがアクセスできるすべてのプロパティを走査し、そのプロパティを現在のオブジェクトに追加することです。
4.3 コードの実装
コードを開発する前に、プログラム全体の実行プロセスを整理する必要があります。
1). ページは ajax リクエストを送信し、パラメーター (ID、ステータス) をサーバーに送信します。
2). サーバー コントローラーはページによって送信されたデータを受信し、サービスを呼び出してデータを更新します
3). サービスはMapperを呼び出してデータベースを操作します
/**
* 根据id修改员工信息
* @param employee
* @return
*/
@PutMapping
public R<String> update(@RequestBody Employee employee){
log.info(employee.toString());
return null;
}
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-FNxCuOsq-1688460908106)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131545374.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-ZHK4wg1i-1688460908106)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131550246.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-tiOF9DeG-1688460908107)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131550257.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-oms8Xy8O-1688460908107)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131550686.png)]
従業員アカウントの有効化と無効化は、基本的には更新操作、つまりステータス フィールドに対する操作です。コントローラーに更新メソッドを作成します。これは、従業員情報を変更するための一般的なメソッドです。
/**
* 根据id修改员工信息
* @param employee
* @return
*/
@PutMapping
public R<String> update(HttpServletRequest request,@RequestBody Employee employee){
log.info(employee.toString());
Long empId = (Long)request.getSession().getAttribute("employee");
employee.setUpdateTime(LocalDateTime.now());
employee.setUpdateUser(empId);
employeeService.updateById(employee);
return R.success("员工信息修改成功");
}
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-BYsdqUYa-1688460908108)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131550918.png)]
コード説明1
上記のコードは、Java Spring Boot フレームワークのコントローラー メソッドです。このコードでは、@PutMapping
アノテーションを使用して、このメソッドが HTTP PUT リクエストを処理することを示します。
このメソッドの目的は、(get 経由で) 提供された従業員 ID に基づいてrequest.getSession().getAttribute("employee")
従業員情報を変更することです。このメソッドのパラメータにはHttpServletRequest
オブジェクトとEmployee
オブジェクトが含まれます。HttpServletRequest
オブジェクトは現在のセッションで従業員 ID を取得するために使用され、Employee
オブジェクトには更新する必要がある従業員情報が含まれます。
コードの実行手順は次のとおりです。
- まず、ロガーはオブジェクトの文字列表現を
log
出力し、受信した従業員情報をログで表示できるようにします。employee
request.getSession().getAttribute("employee")
現在のセッションで従業員 ID を取得し、それを変数に割り当てますempId
。LocalDateTime.now()
現在時刻を取得し、従業員情報の更新時刻として設定する場合に使用します。empId
従業員情報の更新ユーザーとして設定されます。- メソッドを呼び出して、
employeeService.updateById(employee)
データベース内の従業員 ID に対応する従業員情報を更新します。 - 最後に、「従業員情報が正常に変更されました」というメッセージ文字列を含む成功
R
オブジェクトが返されます。
コード内の表現は、R<String>
ジェネリックを含むオブジェクトをString
として返すことに注意してくださいR
。R
これは、ステータス コード、メッセージなど、リクエストの結果を表すために使用されるいくつかのフィールドを含むカスタム応答オブジェクトである場合があります。特定の実装については、プロジェクト内の関連コードを確認する必要がある場合があります。
詳細に
上記のコードは、Java Spring Boot フレームワークのコントローラー メソッドです。このコードでは、@PutMapping
アノテーションを使用して、このメソッドが HTTP PUT リクエストを処理することを示します。
このメソッドの目的は、(get 経由で) 提供された従業員 ID に基づいてrequest.getSession().getAttribute("employee")
従業員情報を変更することです。このメソッドのパラメータにはHttpServletRequest
オブジェクトとEmployee
オブジェクトが含まれます。HttpServletRequest
オブジェクトは現在のセッションで従業員 ID を取得するために使用され、Employee
オブジェクトには更新する必要がある従業員情報が含まれます。
コードの実行手順は次のとおりです。
- まず、ロガーはオブジェクトの文字列表現を
log
出力し、受信した従業員情報をログで表示できるようにします。employee
request.getSession().getAttribute("employee")
現在のセッションで従業員 ID を取得し、それを変数に割り当てますempId
。LocalDateTime.now()
現在時刻を取得し、従業員情報の更新時刻として設定する場合に使用します。empId
従業員情報の更新ユーザーとして設定されます。- メソッドを呼び出して、
employeeService.updateById(employee)
データベース内の従業員 ID に対応する従業員情報を更新します。 - 最後に、「従業員情報が正常に変更されました」というメッセージ文字列を含む成功
R
オブジェクトが返されます。
コード内の表現は、R<String>
ジェネリックを含むオブジェクトをString
として返すことに注意してくださいR
。R
これは、ステータス コード、メッセージなど、リクエストの結果を表すために使用されるいくつかのフィールドを含むカスタム応答オブジェクトである場合があります。特定の実装については、プロジェクト内の関連コードを確認する必要がある場合があります。
要点がわかりません
このメソッドには、HttpServletRequest オブジェクトと Employee オブジェクトの 2 つのパラメータがあります。HttpServletRequest オブジェクトは現在のセッションで従業員 ID を取得するために使用され、Employee オブジェクトには更新する必要がある従業員情報が含まれています。
大変申し訳ありませんが、私の説明のその部分が十分に明確ではなかったかもしれません。メソッドのパラメータとその動作について再度説明します。
-
HttpServletRequest オブジェクト: HttpServletRequest は Java サーブレットのクラスで、クライアントによって発行された HTTP リクエストを表します。このメソッドでは、HttpServletRequest オブジェクトをパラメータとして渡し、現在のセッションで従業員 ID を取得します。
現在のセッションは、クライアント (通常は Web ブラウザ) との対話中にサーバーによって保持されるクライアントに関する情報を指します。セッションは複数の HTTP リクエストにまたがることができ、セッション中はアクティブなままになります。HttpServletRequest オブジェクトを通じて、セッションに格納されている属性値など、セッションに関連する情報を取得できます。
このコードでは、
request.getSession().getAttribute("employee")
セッション内の「employee」という名前の属性の値を取得するために使用します。属性値は、現在ログインしている従業員の ID である必要があります。 -
Employee オブジェクト: Employee は、従業員情報を表すカスタム クラスです。このメソッドでは、更新する必要がある従業員情報を含む Employee オブジェクトをパラメータとして渡します。
従業員オブジェクトには通常、名前、役職、給与などの複数の属性があります。このコードでは、渡す Employee オブジェクトには、更新する必要がある従業員情報が含まれている必要があります。このオブジェクトを通じて、従業員のさまざまな属性値を取得および設定できます。
メソッドの後続のコードでは、Employee オブジェクトのメソッドを使用して従業員の更新時刻を設定し、ユーザーを更新し、それをデータベース内の従業員の情報を更新するために呼び出されるメソッドに渡します
updateById
。
概要: HttpServletRequest オブジェクトは現在のセッションで従業員 ID を取得するために使用され、Employee オブジェクトには更新する必要がある従業員情報が含まれています。これら 2 つのパラメータを通じて、従業員 ID と更新された従業員情報を取得し、更新時間の記録やユーザーの更新などの対応する操作を実行して、データベースを更新できます。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-JgNNzjoe-1688460908108)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131550358.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-RLM1JVjA-1688460908109)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131550262.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-DXCcbbtw-1688460908109)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131551383.png)]
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-sL4IpM3U-1688460908110)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131551952.png)]
F8 5回
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-Uci1NjFu-1688460908110)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131551679.png)]
ID が正しくない 更新に失敗しました
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-5wKFdFBK-1688460908110)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131552765.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-YldLBLMm-1688460908111)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131552126.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-q1Dk3KPi-1688460908111)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131552710.png)]
正しいID
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-MUp6sEQQ-1688460908112)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131552901.png)]
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-A0aS3BKK-1688460908112)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131553078.png)]
4.4 機能テスト
コードを記述した後、プロジェクトを再起動する必要があります。次に、フロントエンド ページにアクセスして、「有効」または「無効」をテストします。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-Ak6gN6U3-1688460908113)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304021806965.png)]
テスト中にエラーは報告されませんでしたが、関数は実装されておらず、データベース内のデータは変更されませんでした。しかし、コンソールに出力されたログを見ると、アップデートが成功していないことがわかります。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-xe7AtMoR-1688460908113)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304021806475.png)]
私たちのデータベースのテーブル構造にはこの ID は存在せず、データベース内の Feng Qingyang に対応する ID は 1420038345634918401 です。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-GTPRcVIU-1688460908113)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304021806756.png)]
4.5 コードの修正
4.5.1 原因分析
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-GcJSgHbQ-1688460908114)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304021806412.png)]
コンソールからの SQL 出力を観察すると、ページに渡された従業員 ID の値がデータベース内の ID 値と一致していないことがわかります。何が起こっているのでしょうか?
ページネーションクエリの際、サーバーは返された R オブジェクトを json 形式にシリアル化し、json 形式のデータに変換します 従業員の ID は Long 型データであり、長さ 19 桁の Long 整数データです。データがフロントエンドに返されることには問題ありません。
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-ptku2prd-1688460908114)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202304021806699.png)]
では、問題は一体どこにあるのでしょうか?
実はこの問題はフロントエンドのJSで発生しており、jsが長さの長い整数データを処理する際に精度が失われ、送信されたIDとデータベース内のIDが不一致になってしまいます。ここで、簡単なテストを行うこともできます。コードは次のとおりです。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
alert(1420038345634918401);
</script>
</head>
<body>
</body>
</html>
4.5.2 解決策
この問題の解決方法も非常に簡単で、jsで処理するIDのデータ型を精度を落とさないように文字列型にするだけです。同様に、テストを実行することもできます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
alert("1420038345634918401");
</script>
</head>
<body>
</body>
</html>
この問題を解決するには、ページネーション クエリによって返される JSON 形式のデータベースの Long 型属性を数値型に直接変換せず、文字列型に変換するだけで済み、最終的に返される結果は次のようになります。 :
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-YZfFYR5I-1688460908114)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304021807347.png)]
4.5.3 コードの修正
SpringMVCではControllerメソッドの戻り値のjsonオブジェクトへの変換はメッセージコンバータMappingJackson2HttpMessageConverterを介したjacksonで実現しているため、メッセージコンバータexpandの機能を実装することでこの問題を解決する必要があります。
具体的な実装手順:
1). Java オブジェクトを Jackson に基づいて JSON データに変換するオブジェクト コンバーター JacksonObjectMapper を提供します (データ内ですでに提供されており、使用するためにプロジェクトに直接コピーされます)。
2). WebMvcConfig 構成クラスで Spring mvc のメッセージ コンバーターを拡張し、このメッセージ コンバーターで提供されているオブジェクト コンバーターを使用して Java オブジェクトを JSON データに変換します。
1). JacksonObjectMapper の導入
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
/**
* 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
*/
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public JacksonObjectMapper() {
super();
//收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化时,属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
.addSerializer(BigInteger.class, ToStringSerializer.instance)
.addSerializer(Long.class, ToStringSerializer.instance)
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//注册功能模块 例如,可以添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}
カスタム オブジェクト コンバーターは主に、JSON データをシリアル化および逆シリアル化するときに LocalDateTime、LocalDate、および LocalTime を処理する方法、および BigInteger および Long 型データを文字列に直接変換する方法を指定します。
2). WebMvcConfig のメソッド extendMessageConverters をオーバーライドします。
/**
* 扩展mvc框架的消息转换器
* @param converters
*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
//创建消息转换器对象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转换器,底层使用Jackson将Java对象转为json
messageConverter.setObjectMapper(new JacksonObjectMapper());
//将上面的消息转换器对象追加到mvc框架的转换器集合中
converters.add(0,messageConverter);
}
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-teHTLONy-1688460908115)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131553415.png)]
テスト
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-MQ5BLdhK-1688460908115)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131553663.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-HDAo2cCe-1688460908116)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131553038.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-l8pLvPDF-1688460908116)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131553871.png)]
F8 4回
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-PQunt52v-1688460908119)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131554063.png)]
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-4ycAP3ya-1688460908119)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131554799.png)]
手放す
再起動
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-QPWiuaow-1688460908119)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131554310.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-BN09ZbqH-1688460908120)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131554974.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-mDQQgjAk-1688460908120)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131554126.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-R0ztbrd4-1688460908121)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131554438.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-m8x4w378-1688460908121)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131554302.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-qYhpXRqz-1688460908122)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131555469.png)]
5. 従業員情報の編集
コードを開発する前に、対応するプログラムの動作プロセスと実行プロセスを整理する必要があります。 1.
編集ボタンをクリックすると、ページが add.html にジャンプし、パラメータ [従業員 ID] が引き込まれます。 URL
2. add.html ページで取得します。 URL 内のパラメータ [従業員 ID]
3. Ajax リクエストを送信し、サーバーにリクエストし、同時に従業員 ID パラメータを送信します。
4. サーバーはリクエストを受信します。従業員 ID に従って従業員情報をクエリし、従業員情報を json 形式でページに応答します
5. ページはサーバーから応答された json データを受け取り、VUE データ バインディングを通じて従業員情報とともにエコーされます
。保存ボタンを押し、ajaxリクエストを送信し、ページ上の従業員情報をjson形式でサーバーに送信 7. サーバーは従業員情報を受信し、
処理を行い、完了後にページに応答します 8
.サーバーからの応答情報に応じて、ページは対応する処理を実行します
注: add.html ページは公開ページであり、従業員の追加と編集は両方ともこのページで実行されます。
1. 編集ボタンをクリックすると、ページは add.html にジャンプし、URL にパラメータ [従業員 ID] が含まれます。
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-erMUGilk-1688460908122)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131555057.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-sEcqqWv7-1688460908123)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306142117010.png)]
2. add.html ページの URL にあるパラメータ [従業員 ID] を取得します。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-eSfqYXtW-1688460908123)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131555202.png)]
3. Ajax リクエストを送信し、サーバーにリクエストし、同時に従業員 ID パラメーターを送信します。
4. サーバーはリクエストを受信し、従業員 ID に従って従業員情報をクエリし、ページに従業員情報を含む応答を返します。 jsonの形式
5. ページはサーバーから応答された JSON データを受信し、VUE のデータ バインディングを通じて従業員情報をエコーします。
報告された 404 は、リクエスト パスの一部としてこの ID を使用しています。
なぜリクエストを送信するのか
リクエストを受信した後、サーバーは ID に従ってユーザーをクエリし、それをページにエコーし、JSON 形式でページに応答することができるためです。
ページはサーバーから応答された JSON データを受け取り、VUE のデータ バインディングを通じて従業員情報をエコーします。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-KztVmtZU-1688460908124)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131555540.png)]
注意点:
変更プロセス中にサーバーとの対話が 2 回あります。
初めてリクエストを送信して、エコーの対応するデータをクエリします。
2 回目に [保存] ボタンをクリックすると、変更したデータがサーバーに送信されます。
5.1 要件分析
従業員管理一覧ページの「編集」ボタンをクリックすると編集ページにジャンプし、編集ページ上の従業員情報を反映して修正し、最後に「保存」ボタンをクリックすると編集作業は完了です。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-pwxDABQA-1688460908124)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304021807123.png)]
上記の分析から、現在実装されている編集機能には 2 つのメソッドを実装する必要があることがわかります。
A. ページ データ エコーに使用される ID に基づくクエリ
B. 変更を保存する
実行プロセス(動画版)
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-8b9eh6MQ-1688460908125)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131555348.png)]
[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-XNx1qGS7-1688460908125)(https://cdn.jsdelivr.net/gh/) zyziga/picodemo/takeaway/day02 /202306131555106.png)]
5.2 プログラム実行の流れ
コードを開発する前に、対応するプログラムの操作プロセスと実行プロセスを整理する必要があります。
1). 編集ボタンをクリックすると、ページは add.html にジャンプし、URL にパラメータ [従業員 ID] が含まれます。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-Ov7g9NOn-1688460908126)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304021807323.png)]
2). add.html ページの URL にあるパラメータ [従業員 ID] を取得します。
3). ajax リクエストを送信し、サーバーにリクエストし、同時に従業員 ID パラメータを送信します。
4). サーバーはリクエストを受信し、従業員 ID に従って従業員情報をクエリし、従業員情報を JSON 形式でページに応答します。
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-0BULTI6z-1688460908126)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202304021807595.png)]
5). ページはサーバーから応答された JSON データを受信し、VUE のデータ バインディングを通じて従業員情報をエコーします。
6). 保存ボタンをクリックし、ajax リクエストを送信し、ページ上の従業員情報を json 形式でサーバーに送信します。
7). サーバーは従業員情報を受信して処理し、完了後にページに応答します。
8). サーバーから応答情報を受信した後、ページは対応する処理を実行します。
注: add.html ページは公開ページであり、従業員の追加と編集は両方ともこのページで実行されます。
5.3 コードの実装
5.3.1 IDによるクエリ
上記の分析後、ID に基づいて従業員情報をクエリすると、要求された情報は次のとおりであることがわかります。
聞く | 説明する |
---|---|
リクエストメソッド | 得る |
リクエストパス | /従業員ID} |
コード:
ID に基づいて従業員情報をクエリするメソッドを EmployeeController に追加します。
/**
* 根据id查询员工信息
* @param id
* @return
*/
@GetMapping("/{id}")
public R<Employee> getById(@PathVariable Long id){
log.info("根据id查询员工信息...");
Employee employee = employeeService.getById(id);
if(employee != null){
return R.success(employee);
}
return R.error("没有查询到对应员工信息");
}
コードの説明
解説1
上記のコードは、Spring フレームワークに基づく Java コード フラグメントであり、RESTful API インターフェイスの実装に使用されます。このコードには、従業員 ID に基づいて従業員情報をクエリするための GET リクエスト メソッドが含まれています。
説明は次のとおりです。
@GetMapping("/{id}")
: HTTP GET リクエストの URL パスを指定するアノテーションです。/{id}
パスに id という名前のパス パラメーターが含まれる必要があることを示します。public R<Employee> getById(@PathVariable Long id)
: これは戻り値の型が R のパブリック メソッドです。R は、API インターフェイスの戻り結果をカプセル化するために使用されるカスタム応答オブジェクトです。このメソッドは getById という名前で、id という名前のパス パラメーターを受け取ります。log.info("根据id查询员工信息...")
: 従業員IDに基づいて従業員情報を照会する操作が実行されていることを示すメッセージをログに記録するためのログ出力文です。Employee employee = employeeService.getById(id)
: これは、employeeService という名前のサービス オブジェクトの getById メソッドを呼び出し、id パラメータを渡して従業員 ID に基づいて従業員情報をクエリします。クエリ結果は従業員オブジェクトに保存されます。if(employee != null)
: 従業員情報がクエリされる場合 (従業員が null でない場合)、コードの次の行を実行します。それ以外の場合は、エラー メッセージを返すロジックを実行します。return R.success(employee)
: 従業員情報がクエリされた場合は、従業員情報を成功応答のデータとして使用し、R.success メソッドを使用して応答結果をカプセル化して返します。return R.error("没有查询到对应员工信息")
: 従業員情報が見つからない場合は、エラー情報をエラー応答のデータとして使用し、R.error メソッドを使用して応答結果をカプセル化してリターンします。
一般に、このコードは GET リクエスト インターフェイスを実装します。このインターフェイスは、従業員 ID を渡すことで対応する従業員情報をクエリし、クエリ結果をカスタム応答オブジェクト R にカプセル化して返します。
解説2
クライアントが指定された URL パス (例: /{id}
) に GET リクエストを送信すると、このメソッドが実行されます。この URL パスには、クエリ対象の従業員の ID を指定するために、id という名前のパス パラメーターが含まれることが想定されます。
メソッド本体内では、まずログ出力を通じて実行中の操作を記録します。つまり、従業員 ID に基づいて従業員情報をクエリします。
次に、employeeService という名前のサービス オブジェクトの getById メソッドを呼び出し、受信した id パラメーターをクエリ条件として使用して、対応する従業員情報を取得します。クエリ結果は、employee という名前のオブジェクトに保存されます。
次に、従業員オブジェクトがnullかどうかを判断することで、従業員情報のクエリが成功したかどうかを判断します。従業員が null でない場合、クエリが成功したことを意味し、従業員情報が成功の応答データとして使用されます。このコードは、R.success メソッドを使用して、応答結果を成功応答オブジェクト R にカプセル化し、それをクライアントに返します。
従業員が null の場合、対応する従業員情報がクエリされていないことを意味します。コードは R.error メソッドを使用してエラー情報をエラー応答オブジェクト R にカプセル化し、クライアントに返します。
つまり、このコード部分は GET リクエスト インターフェイスを実装しており、クライアントは従業員 ID を渡すことで対応する従業員情報をクエリします。クエリが成功した場合は、従業員情報を含む成功応答が返され、クエリが失敗した場合は、エラー情報が含まれたエラー応答が返されます。
詳しく説明してください 従業員employee =employeeService.getById(id); これはあまり明確ではありません、詳しく説明していただけますか
コードがこの行に到達すると、 という名前のサービス オブジェクトのメソッドEmployee employee = employeeService.getById(id);
が呼び出され、パラメータが渡されます。employeeService
getById
id
コードでは、employeeService
これは従業員関連の操作をカプセル化するサービス オブジェクトです。このメソッドを呼び出すと、getById
で渡されたパラメータに従って、id
対応する従業員情報がクエリされます。
ここでのメソッドgetById
には、データベース クエリ操作やその他のデータ取得ロジックが含まれる場合があり、特定の実装はemployeeService
オブジェクトの特定の実装に依存します。渡されたパラメータに従ってデータベースまたは他のデータ ソースにクエリを実行しid
、対応するid
従業員情報を取得します。
クエリ結果はemployee
という名前のオブジェクトに保存されますEmployee
。このオブジェクトには、名前、役職、給与など、クエリされた従業員情報が含まれます。
最後に、employee
そのオブジェクトはその後の判定や処理に使用されます。クエリ結果に応じて、コードは成功応答 (employee
応答データとしてオブジェクトを含む) を返すか、エラー応答 (対応する従業員情報がクエリされていないことを示す) を返すかを決定します。
全体として、Employee employee = employeeService.getById(id);
このコード行の機能は、サービス オブジェクトのメソッドを呼び出して対応する従業員情報を取得し、後続の処理と応答を返すために名前付きのオブジェクトid
にクエリ結果を格納することです。employee
employeeService
従業員情報を処理するサービス オブジェクトです。getById
このメソッドはサービス オブジェクト内の関数であり、その機能は、受信した従業員 ID に従って、対応する従業員情報を取得することです。
コードでは、employeeService.getById(id)
この行を通じてプログラムがgetById
メソッドを呼び出し、それをid
パラメータとして渡します。このようにして、getById
メソッドはどの従業員に情報を問い合わせるべきかを認識します。
getById
このメソッドは、提供された に従って、id
データベースまたは他のデータ ソース内の対応する従業員情報を検索します。クエリの結果は、型のオブジェクトemployee
である という変数に割り当てられますEmployee
。
最後に、クエリ結果の条件に応じて、コードは成功応答を返すかエラー応答を返すかを決定します。従業員情報が正常に見つかった場合は、employee
成功応答としてデータが返されます。該当する従業員情報が見つからない場合は、エラーメッセージが返されます。
簡単に言うと、このコードの目的は、受信した従業員 ID に従ってメソッドemployeeService
を呼び出して、対応する従業員の情報を取得しgetById
、クエリ結果に従って対応する応答を返すことです。
Employee employee = employeeService.getById(id);
従業員情報を取得するためのオブジェクトインスタンスを表します。
employeeService
これは依存関係が注入された Bean であり、メソッドをEmployeeService
定義するインターフェイスを実装しますgetById
。メソッドのパラメータは でid
、戻り値はEmployee
オブジェクトです。
getById
メソッドの実装は、データベースに格納されているid
従業員情報のフィールドを呼び出して、従業員情報のオブジェクト インスタンスを取得します。データベース内の従業員情報がid
渡された値と一致する場合は、従業員情報のオブジェクト インスタンスを返し、それ以外の場合は を返しますnull
。
このインターフェイスは RESTful API として定義されているため、返される従業員情報オブジェクト インスタンスは HTTP 応答ステータス コードと応答ヘッダーの仕様に従う必要があります。通常、応答ステータス コードは 200 (成功) または 404 (リソースが見つかりません) です。
上記のコードでは、従業員情報が空でない場合は、R.success(employee)
従業員情報のクエリが成功したことを示す応答オブジェクトが返され、それ以外の場合は、R.error("没有查询到对应员工信息")
従業員情報をクエリできないことを示すエラー応答が返されます。
テスト
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-4LVFSx7e-1688460908127)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131556298.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-pbVuRtMA-1688460908127)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131557745.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-yhWf808k-1688460908127)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131557489.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-ULIpWPwr-1688460908128)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131557465.png)]
[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-vyjNO7Bc-1688460908128)(https://cdn.jsdelivr.net/gh/zyziga) /picodemo/takeaway/day02 /202306131557210.png)]
5.3.2 従業員の変更
上記の分析後、従業員情報を変更する際に要求される情報は次のとおりであることがわかります。
聞く | 説明する |
---|---|
リクエストメソッド | 置く |
リクエストパス | /職員 |
リクエストパラメータ | {…} json形式データ |
コード:
IDに基づいて従業員情報を更新するメソッドをEmployeeControllerに追加します。
/**
* 根据id修改员工信息
* @param employee
* @return
*/
@PutMapping
public R<String> update(HttpServletRequest request,@RequestBody Employee employee){
log.info(employee.toString());
Long empId = (Long)request.getSession().getAttribute("employee");
employee.setUpdateTime(LocalDateTime.now());
employee.setUpdateUser(empId);
employeeService.updateById(employee);
return R.success("员工信息修改成功");
}
5.4 機能テスト
コードを記述した後、プロジェクトを再起動する必要があります。次に、フロントエンドページにアクセスし、上記で分析した操作プロセスに従ってテストを行い、データが正常に変更されるかどうかを確認します。