St. Regis Takeaway-Day02


title: Regis Takeaway-Day02
abbrlink: '1'
date: 2023-04-1 19:30:00

St. Regis Takeaway-Day02

Course content

  • Perfect login function
  • new employee
  • Employee Information Paging Query
  • Enable/disable employee accounts
  • Edit employee information

Analyze how the front-end page effect is achieved

Why does clicking on the left and right change the root?

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-WwJYwseg-1688460908030)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304092100003.png)]

First of all, let's take a look at how the menu is displayed. Let's take a look at why the right side changes when the menu is clicked.

First: how the menu is displayed

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-a6J6csVc-1688460908031)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304092101695.png)]

When we create a VUE object, we prepare a menuList: [] in our data() position. menuList: [] is an array object

Each JSON data is placed in the array object, and each JSON data contains id name url icon (icon) The above is just the preparation of data, not the definition, so it can be displayed in a position of the menu

<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>

image 3

 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'
                  }
              //   ],
              // },
            ],

Some of the names are 'employee management', 'category management', 'dish management', 'package management', 'order details', which correspond to the ones shown in the figure below.

Figure 4

The above is just the preparation of data, not the definition, which can be displayed in a position of the menu

Second, how to display the position of the menu

Please go to line 39 and use the v-for under the el-menu component to indicate that it is traversing the 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>

Figure 5

所以我们看到的就是以下的名称

Figure 6

如果我们把name修改成id

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VueK0LVa-1688460908036)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02/202304092342644.png)]

重启 刷新

Figure 8

为什么是Id 因为由这个对象数组menuList:[]决定

Figure 9

`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)]

Figure 11

第三 : 点击菜单时 右边会跟着变

http://localhost:8080/backend/index.html

这些菜单实际上都加了一个@click事件 当我们点击菜单的事情 他会执行menuHandle() 方法

  <el-menu-item v-else :index="item.id" @click="menuHandle(item,false)">

Figure 12

然后把item,false传过来 接下来我们找到menuHandle() 方法 在196行

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'
                  }
              //   ],
              // },
            ],

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-FGiI0VQ9-1688460908045)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304100024943.png)]

This is to display a new page through iframeUrl

iframeUrl defined on line 158

iframeUrl: 'page/member/list.html',

image-20230410002610988

Where will iframeUrl be used?

used on line 89

<iframe></iframe>

This is used to display a new page and where does this page come from

            <iframe         //用来展示一个新的页面
              id="cIframe"
              class="c_iframe"
              name="cIframe"
              :src="iframeUrl"
              width="100%"
              height="auto"
              frameborder="0"
              v-show="!loading"
            ></iframe>

image-20230410002952927

This is equivalent to digging a hole on our page

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-HHPZH34n-1688460908048)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304100031207.png)]

And where does this page come from?

 <iframe
              id="cIframe"
              class="c_iframe"
              name="cIframe"
              :src="iframeUrl"   这个地方传进什么数据  展示的就是什么数据
              width="100%"
              height="auto"
              frameborder="0"
              v-show="!loading"
            ></iframe>

image-20230410003635226

Why do we show employee management instead of category management or others after we log in?

This is because we give the iframeUrl an initial value of

 iframeUrl: 'page/member/list.html',

image-20230410003846840

And when we click on the menu, we are actually switching the url

      menuHandle(item, goBackFlag) {
            this.loading = true
            this.menuActived = item.id
            this.iframeUrl = item.url
            this.headTitle = item.name
            this.goBackFlag = goBackFlag
            this.closeLoading()
          },

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-lsGTKVNm-1688460908051)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131532890.png)]

For example, we now modify the initial page to the following

iframeUrl: 'http://www.itcast.c

image-20230410004214015

restart refresh

image-20230410004253475

So when we click on the menu, he is actually switching the url address

And this url address has already been written when the data is prepared

 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'
                  }
              //   ],
              // },
            ],

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-k2oreBW7-1688460908054)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304100044727.png)]

image-20230410004631599

Different menus correspond to different pages, so when we click on a certain menu, it actually switches to the corresponding page

1. Improve the login function

1.1 Problem Analysis

Previously, we have completed the development of the employee login function of the background system, but there is still a problem. Next, we will explain this problem and how to deal with it.

1). Current status

If the user does not log in and directly visits the home page of the system, it can still be accessed normally.

image-20210727232226862

2). Ideal effect

The above design is unreasonable. The effect we want to see should be that the pages in the system can only be accessed after successful login. If there is no login, any interface in the system will directly jump to the login page.

image-20210727232747276

So, how should it be realized?

It can be realized by using the filters and interceptors we explained before, intercepting the requests initiated by the front end in the filters and interceptors, and judging whether the user has logged in. If not, return a prompt message and jump to the login page.

1.2 Thought Analysis

image-20210727233554707

The specific processing logic of the filter is as follows:

A. Get the URI of this request

B. Determine whether this request needs to be logged in before it can be accessed

C. If not required, release directly

D. Judging the login status, if it is already logged in, it will be released directly

E. If not logged in, return the result of not logged in

If not logged in, what kind of results do we need to return to the front end? At this time, we can go to see how the front end handles it?

image-20210728001324901

1.3 Code implementation

Implementation steps:
1. Create a custom filter LoginCheckFilter
2. Add the annotation @ServletComponentScan to the startup class
3. Improve the processing logic of the filter

1). Define the login verification filter

Customize a filter LoginCheckFilter and implement the Filter interface, and complete the verification logic in the doFilter method. Then, we will complete the specific function code implementation according to the above analysis steps:

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-tEBf2g8a-1688460908057)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131533933.png)]

image-20230410010944730

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);
    }
}

image-20230410012037639

reboot

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-JcYZhW6y-1688460908060)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131533957.png)]

to refresh

image-20230410012317239

image-20230410012420126

Code explanation:

explain one

This code is a filter (Filter) in a Java Web application. Filters preprocess the request or response before the request reaches the target Servlet/JSP, so that some operations are done before the actual request is processed.

The function of this filter is to check whether the user has logged in, by checking whether the URL is used to log in the user's authentication information, such as session ID, token, etc. If the user is not logged in, the filter will redirect the user to the login page, if the user is already logged in, the request will be passed to the next handler.

Specifically, this filter implements the doFilter method in the Filter interface. This method receives parameters of ServletRequest and ServletResponse types, and converts them into HttpServletRequest and HttpServletResponse types through type conversion. It then prints a log indicating that the request was intercepted and passes the request and response objects to the FilterChain. Finally, the filter chain passes the request and response objects to the next handler.

In short, this filter is a very useful tool, it can pre-process the user request before reaching the target Servlet/JSP, to ensure that the user has completed the login and has been authorized, thereby protecting the security of the Web application.

Explanation two

When we use a Java web application, we need to make sure that users are logged in and authorized, otherwise they will not be able to access pages that require special permissions. That's what this code does.

This code implements a filter (Filter), which will preprocess the request before reaching the target Servlet/JSP. It checks if the user is already logged in, and if not, it redirects the user to the login page so the user can complete the login, then tries again to access the page that requires special permissions.

This filter checks the requested URL, and if the URL contains the user's authentication information, such as a session ID or token, then it considers the user to be logged in. If the user has not completed the login, it redirects to the login page for the user to complete the login.

The implementation of this filter is relatively simple, it implements the doFilter method in the Filter interface. When a request arrives, it converts the request into an HttpServletRequest object and checks whether the login has been completed. If the login is already done, it passes the request and response objects to the next handler. If the login is not completed, it redirects the user to the login page.

All in all, this filter is a useful tool for securing web applications by ensuring that users are logged in and authorized.

Explanation three

This code is a filter (Filter) in a Java Web application, and its function is to check whether the user has completed the login operation before the user visits any web page.

In the code, the @WebFilter annotation is used, the name of the filter is specified as "loginCheckFilter", and it is applied to all URLs, namely "/*".

In the doFilter() method, convert the incoming ServletRequest and ServletResponse objects into HttpServletRequest and HttpServletResponse objects, record the URL address of the current request, and finally hand over the request and response objects to FilterChain for further processing.

The function of Filter is similar to an interceptor. When a user visits any webpage, the filter will first intercept the request and check whether the user has logged in. If the user has completed the login operation, the filter will release the request and allow the user to continue to visit The page; if the user is not logged in, the filter redirects to the login page, requiring the user to log in before proceeding to the page.

In general, the role of this code is to protect sensitive resources in the Web application, to ensure that only users who have completed the login operation can access these resources, which improves the security of the system.

Understanding: Why is there a forced transfer in this code

In this code, we convert the ServletRequest and ServletResponse objects into HttpServletRequest and HttpServletResponse objects, because the doFilter method of the Filter interface receives ServletRequest and ServletResponse objects, and we need to use HttpServletRequest and HttpServletResponse object to get the HTTP request and response related information.

ServletRequest and ServletResponse are interfaces defined in the Java Servlet Specification that provide a general way of handling HTTP requests and responses. But they lack some methods of HttpServletRequest and HttpServletResponse objects, such as getParameter and getAttribute, which are defined in HttpServletRequest and HttpServletResponse interfaces.

Therefore, in order to be able to use these specific methods, we need to cast the ServletRequest and ServletResponse objects into HttpServletRequest and HttpServletResponse objects, so that these specific methods can be used. However, before casting, we need to make sure that the request is indeed an HTTP request, otherwise the casting may cause a type conversion exception.

Two annotations: explanation of @WebFilter and @Slf4j

The @WebFilter annotation is used to mark a class as a filter (Filter), which can specify the name of the filter (filterName) and the URL pattern (urlPatterns). In this example, we set the name of the filter as "loginCheckFilter" and specify the URL pattern as "/*", that is, intercept all requests.

The @Slf4j annotation is one of the annotations provided in the Lombok framework, which is used to simplify the logging code. It will automatically generate a logger called "log" at compile time, which we can use to log. In this example, we use the log.info method to log information.

These annotations are used to help us write code and implement functions more conveniently. The @WebFilter annotation makes it easier for us to define a filter and specify the requests that need to be intercepted. The @Slf4j annotation helps us implement the logging function more conveniently.

Detailed explanation of each line of code

@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")

This line of code declares a filter using the @WebFilter annotation, specifies the name of the filter as "loginCheckFilter", and applies it to all URLs, namely "/*".

@Slf4j

This line of code uses the @Slf4j annotation provided by Lombok to automatically generate a log object named log, which can be used to output log information.

public class LoginCheckFilter implements Filter {}

This line of code is the declaration of the doFilter() method, which is a method in the Filter interface and is used to intercept user requests and process them.

HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;

This line of code converts the incoming ServletRequest and ServletResponse objects into HttpServletRequest and HttpServletResponse objects for subsequent processing of requests and responses.

log.info("拦截到请求:{}", request.getRequestURI());

This line of code uses the previously defined log object to output a log message, recording the URL address of the current request, which is convenient for subsequent debugging and problem location.

filterChain.doFilter(request, response);

This line of code calls the doFilter() method of the FilterChain object, and passes the processed request and response objects to the next filter or Servlet for processing. If there are no other filters, they are directly handed over to the Servlet for processing. In this way, a chain of filters is formed, ensuring that each request is processed by multiple filters.

review filter filter

explain one

HTTP Request --> Filter 1 --> Filter 2 --> ... --> Filter n --> Servlet --> HTTP Response

In a Java web application, a filter (Filter) is a component used to process HTTP requests and responses. They are used to intercept requests and modify request parameters, headers or body, and response information as needed. Filters can be processed before or after the servlet executes, or while the servlet is processing.

When an HTTP request arrives at the servlet container, it is first intercepted by any registered filters. Filters can alter the request as needed, or pass the request to the next filter. Once all filters have processed the request, the final target servlet is invoked. After the servlet processes the request, it generates a response, which is processed through the same chain of filters, and the response can be modified at each filter.

The order of this filter chain is defined in the web.xml file, and filters can be added or removed dynamically. This allows developers to customize the request processing process as needed, enabling more flexible and complex application functions.

Package: 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 extensions:

Introduction: The path matcher provided in Spring;

Wildcard rules:

symbol meaning
? matches a character
* matches 0 or more characters
** matches 0 or more directories/characters

2). Enable component scanning

It is necessary to add the annotation of Servlet component scanning to the boot class to scan the @WebFilter annotation of the filter configuration. After scanning, the filter will take effect at runtime.

@Slf4j
@SpringBootApplication
@ServletComponentScan
public class ReggieApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(ReggieApplication.class,args);
        log.info("项目启动成功...");
    }
}

The role of @ServletComponentScan:

​ In the SpringBoot project, after adding this annotation to the boot class/configuration class, it will automatically scan the @WebServlet, @WebFilter, @WebListener annotations in the project (under the current package and its subpackages), and automatically register the relevant components of the Servlet ;

1.4 Functional test

When we directly enter

http://localhost:8080/backend/login.html

hour

Will jump to the login interface

http://localhost:8080/backend/page/login/login.html

The front-end JS of the video is different from our actual front-end

After the code is written, we need to restart the project, then directly enter the home page of the system management background in the address bar of the browser, and then check whether it can jump to the login page. We can also track the process of code execution in the form of debug.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-ncOlWYT3-1688460908063)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304021802532.png)]

For the front-end code, debugging can also be performed.

F12 opens the browser's debugging tool, finds the request.js we mentioned earlier, and puts a breakpoint at the response interceptor of request.js.

image-20210728001929657

2. New employees

2.1 Demand Analysis

Employee information can be managed in the background system, and background system users can be added by adding new employees. Click the [Add Employee] button to jump to the new page, as follows:

image-20210728002442334

After filling in the form information and clicking the "Save" button, the data of the form will be submitted to the server, and the server needs to accept the data, and then save the data to the database.

2.2 Data Model

Adding new employees is actually inserting the employee data entered on our new page into the employee table. The status field in the employee table has been set to a default value of 1, indicating that the status is normal.

image-20210728004144521

It should be noted that a unique constraint is added to the username field in the employee table, because username is the employee's login account and must be unique.

image-20210728004250254

2.3 Program execution flow

Before developing the code, we need to combine the requests initiated by the front-end page to sort out the execution process of the entire program:

image-20210728005638224

A. Click the "Save" button, the page sends an ajax request, and submits the data entered in the new employee page to the server in the form of json, the request method is POST, and the request path is /employee

B. The server controller receives the data submitted by the page and calls Service to save the data

C. Service calls Mapper to operate the database and save data

2.4 Code implementation

Add the save method in EmployeeController to save user employee information.

A. When adding an employee, the requirement description in the button page prototype needs to set an initial default password of 123456 for the employee, and encrypt the password with MD5.

B. When assembling employee information, it is also necessary to encapsulate the creation time, modification time, creation person, and modification person information (obtain the current login user from the session).

/*新增员工*/
     @PostMapping
    public R<String> save(@RequestBody Employee employee){
         log.info("新增员工,员工信息:{}",employee.toString());
        return  null;
    }

Ensure that the request sent by the front-end page can be requested to the save method and the submitted parameters can be submitted to the employee object

@RequestBody: Used to obtain the JSON string submitted by the client (front end) and convert the ISON string into a javabeen entity class

@RespomseBody: javabeen entity class converted to JSON

Employee: Use the Employee object to receive the request parameters passed by the front end (JSON format)

R: return value

General explanation 1

This code is a controller method that uses the Spring framework to process HTTP POST requests and map the data in the request body to Employee objects to add employees.

Let's explain the code line by line:

  • @PostMapping: This is an annotation used to map this method to the HTTP POST request method. It indicates that this method will handle POST requests from clients.
  • public R<String> save(@RequestBody Employee employee): This is the declaration of the method. It receives a Employeeparameter of type which will be extracted from the request body. @RequestBodyThe annotation tells the Spring framework to take JSON data from the request body and convert it into Employeean object.
  • log.info("新增员工,员工信息:{}", employee.toString()): This line of code uses logging to record the operation of adding an employee. log.info()method is used to print information, and use placeholders {}to employee.toString()insert the return value of 's into the log information. This allows you to view the details of the newly added employee in the console or in the log file.
  • return null: This method returns a nullvalue. You can return an appropriate response according to actual needs, such as returning a success message or the ID of the new employee.

So, when you send a HTTP POST request to the URL of this controller, the data in the request body will be mapped to the Employeeobject, and the employee's information will be printed in the log. The method will then return a nullvalue in response. You can modify the method body according to your needs, execute appropriate business logic or return corresponding results.

General explanation 2

This code is an interface for new employee functions of the employee management system based on the SpringBoot framework.

Among them, the @PostMapping annotation indicates that the interface only accepts POST requests. The @RequestBody annotation indicates that the JSON format data in the request body is bound to the Employee object. The Employee object represents an employee's information, including attributes such as employee ID, name, gender, and position. When receiving the POST request from the client, SpringBoot will automatically convert the JSON format data in the request body into the corresponding Employee object, and assign it to the method parameter employee.

Inside the method, use log.info to print out the newly added employee information. Finally, the type returned by the interface is R, which represents a custom response class, where R represents the response result, and String represents the content of the response message. In this example, the interface returned null. Null needs to be replaced with the corresponding response result according to actual business needs.

In short, the main function of this code is to receive the employee information submitted by the client and write it to the database, record the log and return the response result.

image-20230605105616707

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-GkG6Hg4I-1688460908065)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306051054661.png)]

image-20230605105816824

image-20230605105845333

/**
 * 新增员工
 * @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("新增员工成功");
}

code explanation 1

This code is a controller method using the Spring framework to handle HTTP POST requests and add employees.

Let's explain the code line by line:

  • @PostMapping: This is an annotation that maps this method to the HTTP POST request method.
  • public R<String> save(HttpServletRequest request, @RequestBody Employee employee): This is the declaration of the method. It receives two parameters: HttpServletRequest requestand Employee employee. @RequestBodyAnnotations tell the Spring framework to take data from the request body and convert it into Employeean object. HttpServletRequestParameters are used to get information about the current request.
  • log.info("新增员工,员工信息:{}", employee.toString()): This line of code uses logging to record the operation of adding an employee. Employee information is employee.toString()converted to a string and inserted into the log information.
  • employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes())): This line of code sets the employee's initial password to "123456" and encrypts it with MD5. DigestUtils.md5DigestAsHex()method converts a byte array to an MD5 hashed string.
  • employee.setCreateTime(LocalDateTime.now()): This line of code sets the current time as the employee's creation time.
  • employee.setUpdateTime(LocalDateTime.now()): This line of code sets the current time as the employee's update time.
  • Long empId = (Long) request.getSession().getAttribute("employee"): This line of code gets an attribute named "employee" from the current session, which represents the ID of the currently logged in user.
  • employee.setCreateUser(empId)and employee.setUpdateUser(empId): These two lines of code set the ID of the currently logged in user as the employee's create user and update user.
  • employeeService.save(employee): This line of code calls the method employeeServiceof the service save()to save the newly added employee information.
  • return R.success("新增员工成功"): This line of code returns a successful response, containing a "New employee successful" message.

To sum up, this code processes an HTTP POST request, maps the data in the request body to an Employeeobject, and performs a series of processing on the object, such as setting the initial password, setting the creation time and update time, setting the creation user and updating the user wait. Finally, call employeeServicethe save()method to save the employee information and return a successful response message.

Code Explanation 2

This code is an interface for the new employee function of the employee management system based on the SpringBoot framework, which adds some business logic processing compared to the previous code.

Among them, the @PostMapping annotation indicates that the interface only accepts POST requests. The @RequestBody annotation indicates that the JSON format data in the request body is bound to the Employee object. HttpServletRequest request represents HTTP request information. The Employee object represents an employee's information, including attributes such as employee ID, name, gender, and position.

Inside the method, use log.info to print out the newly added employee information. Next, some preprocessing operations are performed on the employee object:

  1. Set the initial password 123456, and encrypt it with MD5 and store it in the employee object;
  2. Get the current time and set it as the creation time and update time respectively;
  3. Get the id of the currently logged in user from the session, and set it as the user creation and update user;

Finally, call the employeeService.save() method to write the employee information into the database, and return a custom response class R when the interface returns, where success indicates the status of success, and "new employee succeeded" indicates the content of the response message.

In short, the main function of this code is to receive the employee information submitted by the client and write it into the database, and perform some preprocessing operations. At the same time record the log and return the response result.

Test new employees

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-TLxlqAru-1688460908067)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131535557.png)]

image-20230605112841758

image-20230605112910313

There will be problems if you enter a zhagsan

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-sYFBDM4l-1688460908070)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131535685.png)]

image-20230605113648946

image-20230605113727456

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-oakWy0Xb-1688460908072)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306052104630.png)]

2.5 Functional test

After the code is written, we need to restart the project. After the completion, directly visit the homepage of the management system, click the "Add Employee" button on the "Employee Management" page, enter the basic information of the employee, and then click "Save" to save the data. After saving , to check whether the employee data is entered in the database.

When we add a user in the test and enter an existing user name, an error message appears on the front-end interface:

image-20210728010841569

At this time, the server has reported an error, and the error message is as follows:

image-20210728010938086

The above error occurs mainly because in the employee table structure, we have established a unique index for the username field. When adding duplicate username data, if the constraint is violated, an error will be reported. But at this time, the information prompted by the front end is not specific, and the user does not know what caused the exception. We need to prompt the user with detailed error information.

2.6 Global exception handling

2.6.1 Idea Analysis

In order to solve the problems in the above tests, we need to capture the exceptions that may occur in the program. There are usually two ways to deal with them:

A. Add try...catch to the Controller method for exception capture

The form is as follows:

image-20210729094125294

If this method is used, although it can be solved, there are disadvantages. When we save other business data, we also need to add try...catch to the Controller method for processing. The code is redundant and not universal.

B. Use exception handlers for global exception capture

In this way, we only need to define a general global exception handler in the project to resolve all exceptions in this project.

2.6.2 Global exception handler

Customize a global exception handler in the project, add the annotation @ControllerAdvice to the exception handler, and specify which type of Controller method to intercept through attribute annotations. And add the annotation @ExceptionHandler to the method of the exception handler to specify which type of exception is intercepted.

Exception handling method logic:

  • Specify the caught exception type as SQLIntegrityConstraintViolationException
  • Parse the exception prompt information, and get the value that violates the unique constraint
  • Assemble the error message and return
image-20210729100232642
/**
 * 全局异常处理
 */
@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("失败了");
    }
}

Code explanation 1:

The above code is a class for global exception handling. This class uses Spring's @ControllerAdvice annotation to identify it as a global exception handler. Through this annotation, it intercepts exceptions that occur in classes annotated by @RestController and @Controller annotations.

The specific explanation is as follows:

  1. @ControllerAdvice(annotations = {RestController.class, Controller.class}): This is a class-level annotation used to specify the annotation type of the Controller class to be intercepted by the global exception handling class. Here, it specifies that the class to be intercepted must be a class marked with @RestController or @Controller annotation.
  2. @ResponseBody: This is a method-level annotation, indicating that the return value of this method will be directly returned to the client as the content of the response, rather than being parsed into a view by the view resolver. Here, it ensures that the return value of the exception handling method will be converted to the JSON format of the response.
  3. @ExceptionHandler(SQLIntegrityConstraintViolationException.class): This is a method-level annotation that specifies the specific exception type to be handled by the method. Here, it specifies that the exception to be handled by the method is SQLIntegrityConstraintViolationException.
  4. public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex): This is the exception handling method, which receives a parameter of type SQLIntegrityConstraintViolationException, which represents the caught exception object. The return type of the method is R, and R is a custom generic response object used to wrap the response data.
  5. log.error(ex.getMessage()): This line of code uses the logging function provided by Slf4j to record the abnormal error message to the log.
  6. return R.error("失败了"): This line of code returns an R object representing the response result after handling the exception. Use the R.error static method to create an R object of type error and set the error message to "failed".

综上所述,以上代码定义了一个全局异常处理类,用于捕获和处理Controller层中发生的SQLIntegrityConstraintViolationException异常,并将错误信息记录到日志中,最后返回一个错误类型的响应结果。

代码解释2

这段代码是一个基于SpringBoot框架的全局异常处理类,用于捕获并处理SQL异常。

@ControllerAdvice注解表示该类用于全局异常处理。通过annotations参数指定了需要拦截的控制器注解类型为@RestController和@Controller。@ResponseBody注解表示返回的是JSON格式的数据。@Slf4j注解表示使用log记录日志。

@ExceptionHandler注解表示该方法用于捕获SQLIntegrityConstraintViolationException类型的异常。当系统出现SQLIntegrityConstraintViolationException类型的异常时,会调用该方法进行异常处理。在方法内部,使用log.error打印异常信息,并返回一个自定义的响应类R,其中error表示失败的状态,"失败了"表示响应消息的内容。

总之,这段代码的主要作用是实现对SQLIntegrityConstraintViolationException类型异常的统一捕获和处理。当系统出现该类型的异常时,会执行该方法进行异常处理,并记录日志并返回响应结果。

image-20230605205207722

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oGQEzmmS-1688460908073)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02/202306131536773.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-zDnZxiTx-1688460908074)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131536460.png)]

image-20230605213228144

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-m2WjK5TB-1688460908076)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131536013.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-gT3qFPmr-1688460908076)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131536837.png)]

Package: 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("未知错误");
    }
}

Notes:

​ The two annotations @ControllerAdvice and @ResponseBody used on the above global exception handler are as follows:

​ @ControllerAdvice : Specifies which types of controllers to intercept;

​ @ResponseBody: convert the return value R object of the method into data in json format, and respond to the page;

​ The two annotations used above can also be combined into one annotation @RestControllerAdvice

image-20210729100052940

image-20230605214040718

code explanation 1

The above code is a Java class that contains an GlobalExceptionHandlerexception handling class named . This class contains a exceptionHandlermethod named , which receives a SQLIntegrityConstraintViolationExceptiontype of exception as a parameter.

In exceptionHandlerthe method, first use log.error(ex.getMessage())the method to save the exception message to the log. Then, use ex.getMessage()the method to get the exception message and split it into multiple strings for further processing.

If the exception message contains a string "Duplicate entry", the method will use split()the method to split the string into multiple strings, and then get the 3rd string from it, which is usually details describing the presence of duplicates. Finally, the method will use error()the method to convert the details into R<String>a response of type and return that response. If the exception message contains other strings, the method will return R.error("未知错误")a response of type .

It should be noted that @ExceptionHandlerthe annotations in this code are used to specify the type of exception handled and return R<String>the type of data. This annotation needs to @RestControllerbe used with annotations to integrate exception handling with RESTful API.

explaining in detail

The annotation in the above code @ExceptionHandleris an exception handling annotation, which is used to specify which type of exception to handle. In this example, @ExceptionHandler(SQLIntegrityConstraintViolationException.class)the method is specified to handle SQLIntegrityConstraintViolationExceptionexceptions of type.

@ExceptionHandlerThe annotation takes one parameter, the type of exception to handle. In this example, SQLIntegrityConstraintViolationExceptionis the exception type we want to handle. When the program encounters such an exception, it will be passed to exceptionHandlerthe method for handling.

exceptionHandlerA method is a return value method that receives a SQLIntegrityConstraintViolationExceptiontype of exception as a parameter. Inside the method, we first use log.error(ex.getMessage())the method to save the exception message to the log. We then use ex.getMessage()the method to get the exception message and split it into multiple strings.

If the exception message contains a string "Duplicate entry", the method will use split()the method to split the string into multiple strings, and then get the 3rd string from it, which is usually details describing the presence of duplicates. In this example, we pass the 3rd string as a parameter to error()the method to convert the details into R<String>a typed response. If the exception message contains other strings, the method will return R.error("未知错误")a response of type .

Finally, we need to integrate exception handling with the RESTful API. In this example, @RestControllerthe annotation specifies that the controller handles RESTful API requests. So when the program encounters an exception, it will be passed to the exception handling function in the RESTful API controller. In this case, the function uses @ExceptionHandlerannotations to specify the type of exception to handle and returns an error response.

Code Explanation 2

The above code is a global exception handler, which is used to catch the exception thrown in the controller marked by @RestController or @Controller, and return the error message in a unified format.

Among them, the @ControllerAdvice annotation indicates that this class is a global exception handler, the @ResponseBody annotation indicates that the returned result is data in JSON format, and @Slf4j is a Slf4j logging tool, which is often used to output log information.

In terms of code implementation, the @ExceptionHandler annotation is used to specify the type of exception handled and return data of type R.

The processing flow of this code is: when an exception of SQLIntegrityConstraintViolationException is caught, if the exception information contains the words "Duplicate entry", it is considered to be an exception of data duplication, the specific data is extracted from the exception information, and then a message containing the information is returned Data of type R; otherwise, an "unknown error" data of type R is returned.

Code Explanation 3

The above code is a global exception handling class that uses the @ControllerAdvice annotation provided by the Spring framework. This class is used to catch and handle exceptions thrown in controllers.

Annotations in the code @ControllerAdvice(annotations = {RestController.class, Controller.class})indicate that the class will only handle exceptions that occur in controllers annotated with @RestControlleror .@Controller

The annotation @ResponseBodyindicates that the result returned by the method of this class will be returned directly as the response body instead of being parsed as a view by the view resolver. It is to convert javabeen into JSON and return

@Slf4jis a Lombok annotation for automatically generating loggers.

@ExceptionHandler(SQLIntegrityConstraintViolationException.class)Indicates that the method will handle SQLIntegrityConstraintViolationExceptionexceptions of type. In the method, it first records the error message of the exception, and then checks whether the error message contains "Duplicate entry", and if so, generates the corresponding error message according to the content of the error message and returns an object (possibly Rcustom response object).

If the error message does not contain "Duplicate entry", an object containing the default error message is returned R.

It's worth noting that this line of code in the code 返回 R.error(msg);is pseudocode and should actually return an Robject. In this case, R.error(msg)a pseudocode that means return an object with an error msgmessage R. The specific Robject implementation and usage methods need to be defined and processed according to the actual situation.

Summary: The above code is a global exception handling class for catching and handling exceptions thrown in the controller SQLIntegrityConstraintViolationException. According to the error message of the exception, it generates the corresponding error message and returns an Robject (pseudo-code) used to represent the exception handling result.

explain in detail

When developing with the Spring framework, we often need to handle exceptions that may be thrown in the controller to provide better error handling and friendly error responses. The global exception handling class is used for this purpose.

First, we can use @ControllerAdviceannotations to identify a class as a global exception handling class. In this example, the annotation uses annotationsattributes specifying the type of controller annotation that needs to be processed as @RestControllerand @Controller.

Next, use @ExceptionHandlerthe annotation to identify a method as an exception handler. In this case, the method handles SQLIntegrityConstraintViolationExceptionan exception of type .

In the exception handling method, we first use @Slf4jthe annotation to generate a logger to record the exception's error message.

Next, we check whether the exception's error message contains "Duplicate entry", that is, whether it is an exception thrown because of a violation of the uniqueness constraint (Duplicate entry). If so, we extract the corresponding information from the error message and generate a new error message based on that information.

In this example, we use ex.getMessage().contains("Duplicate entry")to check whether the error message contains "Duplicate entry", and then use ex.getMessage().split(" ")to split the error message by spaces to obtain relevant information.

After generating a new error message, we R.error(msg)create a response object with msgthe error message. Here R.error()is a pseudocode that returns a response object with an error message.

If the error message does not contain "Duplicate entry", it means other unknown errors, and we return a default error response object, which contains a default error message indicating an unknown error.

It should be noted that 返回 R.error(msg);this line of code in the code is pseudocode, and should actually return an Robject, and the specific return method needs to be defined and processed according to the actual situation.

By using this global exception handling class, we can centrally handle the specified types of exceptions thrown in the controller and provide custom error responses. This simplifies code logic and provides a unified exception handling mechanism to improve system robustness and user experience.

When we add an existing value

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-yYdGR7gY-1688460908077)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131537709.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-LPG10VAA-1688460908078)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131537244.png)]

When we add a value that does not exist

image-20230605220456101

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-ZxaVZMON-1688460908079)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131537941.png)]

image-20230605220526780

2.6.3 Testing

After the global exception handler is written, we need to restart the project, and then directly visit the homepage of the management system, and click the "Add Employee" button on the "Employee Management" page. When we add a user in the test and enter an existing user name, the front-end interface displays the following error message:

image-20210729102220135

image-20230605220945408

3. Employee page query

3.1 Demand Analysis

When there are a lot of employees in the system, it will be messy to display all of them on one page, which is not easy to view. Therefore, in general systems, the list data will be displayed in a page-by-page manner. In our pagination query page, in addition to the pagination condition, there is also a query condition such as the query "employee name".

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-Dgn6vaVn-1688460908081)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304021803131.png)]

  • request parameters

    • Search criteria: employee name (fuzzy query)

    • Pagination conditions: number of items displayed on each page, page number

  • response data

    • total
  • result list

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-gbQrUaTx-1688460908082)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131538518.png)]

1). The page sends an ajax request, and submits the pagination query parameters (page, pageSize, name) to the server

F12 refresh page

image-20230605221857857

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-kXxtcVB6-1688460908083) (C:\Users\zyz\AppData\Roaming\Typora\typora-user-images\ image-20230605221909418.png)]

page=1&pageSize=10 Check the first page and check 10 data in total

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-p1zw7eSO-1688460908084)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131538788.png)]

Look at the front-end code

image-20230605222232623

Why is the request sent out as soon as it is loaded?

 <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>

The above code is a front-end page script written using the Vue framework. It creates a Vue instance, which contains some data and methods.

dataFirst, some data is defined in the properties of the Vue instance , including input(the value of the input box), counts(the total number of data), page(the current page number), pageSize(the amount of data displayed on each page), tableData(table data), id(employee ID), status(employee status), etc.

In createdthe lifecycle hook function, userInfoassign the account number of the currently logged-in employee to userthe data by reading the browser's local storage (localStorage).

In mountedthe life cycle hook function, you can perform some operations that need to be performed after the page is loaded, but there is no specific logic in this code snippet.

Next is the definition of some methods:

  1. initMethod: This method is used to initialize the page data. It getMemberListobtains the employee list data by calling the function, and assigns the returned data to tableDataand counts.
  2. handleQueryMethod: When the user clicks the query button, pagereset the page number ( ) to 1, and then call initthe method to reload the data.
  3. addMemberHandleMethod: used to handle the operation of adding or modifying employees. According to the incoming parameter st(can be 'add' or employee ID), call the window.parent.menuHandlemethod to open the corresponding page to add or modify employees.
  4. statusHandleMethod: Used to handle account state changes. First assign the employee's ID and status to idand status, and then pop up a confirmation dialog box. After confirming the adjustment of the account status, call enableOrDisableEmployeethe function to send a request to change the employee's status. If the request is successful, a success message is displayed and handleQuerythe method is called to reload the data.
  5. handleSizeChangeMethod: When the user changes the amount of data displayed on each page, assign the new data amount to pageSize, and then call initthe method to reload the data.
  6. handleCurrentChangeMethod: When the user changes the current page number, assign the new page number to page, and then call initthe method to reload the data.

To sum up, the above code mainly implements a front-end page for employee management, including functions such as employee list display, query, addition, modification, and account status change.

function getMemberList (params) {
  return $axios({
    url: '/employee/page',
    method: 'get',
    params
  })
}

The above code defines a getMemberListfunction named , which takes a paramsparameter named .

This function uses $axiosan object (probably a library that encapsulates an Ajax request) to send a GET request to the requested URL /employee/page. The parameters of the request paramsare passed using an object, and the method of the request is set to GET.

After the function is executed, a Promise object will be returned, and the result or error of the request can be processed through the .then()method .catch().

In short, this function is used to send a GET request to the specified URL, and the parameters are the parameters in paramsthe object to obtain the data of the employee list.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-d7wxrkJk-1688460908085)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131538116.png)]

3.2 Program execution flow

3.2.1 Page flow analysis

Before developing the code, you need to sort out the execution process of the entire program.

A. Click the menu to open the employee management page, execute the query:

image-20210729163400772

B. Enter the employee's name in the search bar, press Enter, and execute the query:

image-20210729164259997

1). The page sends an ajax request, and submits the pagination query parameters (page, pageSize, name) to the server

2). The server controller receives the data submitted by the page, and assembles the conditions to call the Service to query the data

3). Service calls Mapper to operate the database and query paged data

4). The Controller will respond to the paged data queried to the front-end page

5). The page receives the paged data and displays it on the page through the Table component of ElementUI

3.2.2 Front-end code introduction

1). When accessing the employee list page /member/list.html, the hook method in Vuejs will be triggered, and the created method will be called when the page is initialized

image-20210729231639034

From the above front-end code, we can see that after executing the pagination query, the information we need to return to the front-end needs to contain two items: the list of results encapsulated in records, and the total number of records encapsulated in total.

When assembling the request parameters, page and pageSize are the parameters when the front-end paging plug-in renders;

image-20210729232916380

2). In the getMemberList method, initiate an asynchronous request through axios

image-20210729231745143

The asynchronous request initiated by axios will be intercepted by the request interceptor declared in request.js, in which the get request will be further packaged and processed

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-sBOP16Mi-1688460908087)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304021804051.png)]

The final request sent to the server is: GET request, request link /employee/page?page=1&pageSize=10&name=xxx

3.3 Code implementation

3.3.1 Paging plugin configuration

Currently we want to implement the paging query function, but to implement the paging function in MybatisPlus, we need to use the paging plug-in provided in MybatisPlus. To use the paging plug-in, we must declare the bean object of the paging plug-in in the configuration class.

Belonging package: 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;
    }
}

code explanation 1

The above code is a Java class used to configure the paging plug-in of MyBatis-Plus (MP for short).

  1. @ConfigurationThe annotation indicates that this is a configuration class used to configure some components or functions of the application.
  2. MybatisPlusConfigA named Bean method is defined in the class mybatisPlusInterceptorto create and return an MybatisPlusInterceptorobject.
  3. MybatisPlusInterceptorIt is an interceptor provided by MyBatis-Plus, which is used to intercept the SQL execution process of MyBatis and add additional functions during the execution process. addInnerInterceptorAdd an PaginationInnerInterceptorobject as MybatisPlusInterceptoran internal interceptor by calling a method.
  4. PaginationInnerInterceptorIt is a paging plug-in provided by MyBatis-Plus, which can automatically intercept SQL statements and perform paging queries according to the incoming paging parameters. After PaginationInnerInterceptoradding it to MybatisPlusInterceptor, you can realize automatic pagination of query results.
  5. @BeanThe annotation indicates that the object returned by the method is registered as a Spring Bean, which can be used in other components through dependency injection.

To sum up, the above code configures the paging plug-in of MyBatis-Plus, and realizes the automatic paging function of MyBatis by creating MybatisPlusInterceptoran object and adding it as an internal interceptor.PaginationInnerInterceptor

be more detailed

When using the MyBatis-Plus framework for database operations, sometimes it is necessary to display query results in pages. The above code shows how to configure the paging plugin of MyBatis-Plus.

First, create a Java class and add @Configurationannotations to indicate that this is a configuration class. The main purpose of this class is to configure the paging plugin of MyBatis-Plus.

In this configuration class, a mybatisPlusInterceptormethod named is defined and @Beanmarked with an annotation. This means that the object returned by this method will be registered as a Spring Bean and can be used in other components through dependency injection.

In mybatisPlusInterceptorthe method, an object is created MybatisPlusInterceptorand configured. MybatisPlusInterceptorIt is an interceptor provided by the MyBatis-Plus framework, which can add additional functions during the execution of MyBatis SQL statements.

addInnerInterceptorAdd an PaginationInnerInterceptorobject to it as an internal interceptor by calling the method MybatisPlusInterceptor. PaginationInnerInterceptorIt is a paging plug-in provided by MyBatis-Plus, which can intercept SQL statements and automatically perform paging queries according to the incoming paging parameters.

In this way, the automatic paging function of MyBatis is realized through the configured MybatisPlusInterceptorinternal interceptor .PaginationInnerInterceptor

To sum up, the above code configures the paging plug-in of MyBatis-Plus, so that when using MyBatis-Plus for database query, the paging operation can be conveniently performed, so that the query results can be displayed in batches on the page. In this way, developers do not need to manually write paging logic, but let the paging plug-in automatically intercept SQL statements and perform paging queries according to the incoming paging parameters, which simplifies the development process.

Code Explanation 2

This code implements the configuration of the MyBatis Plus pagination plugin. MyBatis Plus is an enhanced tool based on MyBatis, which provides some powerful functions while improving development efficiency, one of which is the pagination plug-in.

In this code, we define a MybatisPlusInterceptor instance and add a PaginationInnerInterceptor internal interceptor to it, which is used to implement the paging function. Finally, register the MybatisPlusInterceptor instance as a Bean in the Spring container to complete the configuration of the MyBatis Plus paging plugin.

Code Explanation 3

The above code is a configuration class of MyBatis-Plus, which defines a named mybatisPlusInterceptorBean. The role of this bean is to use the Pagination plug-in in MyBatis-Plus for pagination processing.

In mybatisPlusInterceptorthe method, we create a MybatisPlusInterceptornew object called and return it. This object is an interceptor object that can be intercepted before or after executing SQL operations. Here, we add an internal interceptor PaginationInnerInterceptorfor pagination when query operations are performed.

PaginationInnerInterceptorIs a custom internal interceptor, its function is to divide the query statement into multiple parts when executing the query operation, and perform paging processing on each part as needed. In this example, we set the size of each part to 10, which means that the size of each part is 10 records.

After returning MybatisPlusInterceptorthe object, we can define methods in the configuration file @Beanto create the object. In this case, MybatisPlusConfigthe class is a configuration class that defines a @Beanmethod mybatisPlusInterceptorto create MybatisPlusInterceptorobjects.

By defining methods in the configuration file @Beanto create MybatisPlusInterceptorobjects, we can automatically configure MyBatis-Plus at application startup for pagination when executing queries.

be more detailed

MyBatis-Plus is an open source persistence layer framework, which provides many functions, such as automatic table creation, dynamic SQL, transaction management and so on. Among them, the pagination plug-in is an important function provided by MyBatis-Plus, which can help developers to perform paging processing more conveniently.

The class in the above code MybatisPlusConfigis a configuration class, which defines a @Beanmethod mybatisPlusInterceptorfor creating MybatisPlusInterceptorobjects. This object is an interceptor object that can be intercepted before or after executing SQL operations. Here, we have added an internal interceptor PaginationInnerInterceptor, its function is to divide the query statement into multiple parts when executing the query operation, and paginate each part as needed.

PaginationInnerInterceptoris a custom internal interceptor that inherits from MyBatisPlusInterceptorthe class. MyBatisPlusInterceptorClass is the default interceptor class provided by MyBatis-Plus, which provides some basic interception functions, such as SQL filtering, transaction management, exception handling and so on. In PaginationInnerInterceptorthe class, we override some of these methods, for example beforeQuery, to do pagination before querying.

In beforeQuerythe method, we use String.split()the method to split the query into parts and pass each part as a parameter to the method MyBatisPlusInterceptorof beforeQuerythe . In beforeQuerythe method, we can use MapperScannerConfigurerthe class to scan and configure the Mapper interface to perform corresponding operations when querying.

Through the above code, we can implement the paging function in MyBatis-Plus without modifying the source code of MyBatis-Plus. @BeanAt the same time, we can also define methods in the configuration file to create MybatisPlusInterceptorobjects so that MyBatis-Plus can be automatically configured when the application starts, thereby improving the maintainability and scalability of the system.

3.3.2 Paging query implementation

As we have analyzed above, when the page performs pagination query, the specific request information is as follows:

ask illustrate
request method GET
request path /employee/page
request parameters page , pageSize , name

So what kind of results do we need to return to the front end after the query is completed?

We also analyzed above that the result data returned by the query should encapsulate two pieces of information, namely: records encapsulates the paging list data, and total encapsulates the total number of records that meet the conditions. Then at this time, when defining the return value type R of the controller method, we can directly encapsulate and return the result Page of the MybatisPlus pagination query, because the properties in the Page are as follows:

image-20210729235403154

Then, based on these known requirements and conditions, the code implementation of pagination query is completed. The specific logic is as follows:

A. Construct pagination conditions

B. Build search criteria - name for fuzzy matching

C. Build sorting conditions - sort in reverse order of update time

D. Execute the query

E. Assemble the result and return

records   结果列表
total     总记录数   

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-CXUtqRG7-1688460908088)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131539429.png)]

image-20230606082032620

Receive the response from the server

   await getMemberList(params).then(res => {
              if (String(res.code) === '1') {
                this.tableData = res.data.records || []
                this.counts = res.data.total
              }
            }

The data returned by the server

 this.tableData = res.data.records || []
 this.counts = res.data.total

This means that the JSON we respond to should have records total fields, but our Employee does not have these two fields, so the generic type we use in EmployeeController should be Page Page is a class encapsulated by MybatisPlus for us. We will perform paging query in a while. It will also return this object as shown below

In our Page, we have our .records and total attributes. Records is the list data displayed on the current page, the total total number of records, and the total number of records. So why we use Page here is because the data records and total are required on the page.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-hzsRlDjw-1688460908089)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131539517.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-7cVWiVjr-1688460908090)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131540157.png)]

  public  R<Page> page() {

         return  null;

      }

image-20230606083713938

  /**
     * 员工信息分页查询
     * @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;
      }

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-jryzYHDC-1688460908091)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131540813.png)]

Refresh the page and log in

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-lgQ7Anmi-1688460908092)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131540365.png)]

F8

image-20230606084530751

let go

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-3yuxSMuq-1688460908092)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131540621.png)]

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-Nvr0TdpU-1688460908093)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131540085.png)]

image-20230606084723825

The specific code implementation is as follows:

/**
 * 员工信息分页查询
 * @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);
}

code explanation 1

The above code is an interface method for employee information paging query in Java Spring Boot. Here is an explanation of the code:

  1. @GetMapping("/page"): This is the mapping path of a GET request, which is used to handle pagination query requests. The request path is /page.
  2. public R<Page> page(int page, int pageSize, String name): This is a public method with a return type of , R<Page>that is, an object that wraps the response result. The method name pageaccepts three parameters: pagethe page number of the current query, pageSizethe number of records displayed on each page, nameand the employee name (optional parameter).
  3. log.info("page = {},pageSize = {},name = {}", page, pageSize, name): This line of code is used to output the log and record the parameter value passed in.
  4. Page pageInfo = new Page(page, pageSize): This is a pagination constructor used to create a paging object, passing in the page number of the current query and the number of records displayed on each page.
  5. LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper(): This is a condition constructor, which is used to construct the query condition object.
  6. queryWrapper.like(StringUtils.isNotEmpty(name), Employee::getName, name): This line of code adds a fuzzy query condition to perform fuzzy matching based on employee names ( Employeeobject attributes). It is used to judge whether the parameter is not empty, if not, add the fuzzy query condition; otherwise, do not add the condition.nameStringUtils.isNotEmpty(name)name
  7. queryWrapper.orderByDesc(Employee::getUpdateTime): This line of code adds a sorting condition to sort in descending order based on the employee's update time (a property Employeeof the object ).updateTime
  8. employeeService.page(pageInfo, queryWrapper): This line of code executes the query operation, calls employeeServicethe pagemethod, passes in the paging object and query condition object, and encapsulates the query result into pageInfothe object.
  9. return R.success(pageInfo): Finally, the object that encapsulates the query result pageInfois used as the response result, and R.success()returned after being wrapped by the method.

Generally speaking, this interface method accepts the parameters of the pagination query, builds the query condition according to the parameters, executes the query operation, and returns the paging object containing the query results.

What is StringUtils in this

StringUtilsIs a string processing tool class, usually a class in the Apache Commons Lang library. It provides many utility methods for processing strings, such as determining whether a string is empty, removing spaces in strings, comparing strings, etc.

In the code, StringUtils.isNotEmpty(name)it is used to judge namewhether the parameter is empty. Returns if namenot empty true; returns if nameempty or null false. This judgment condition is used to decide whether to add the fuzzy query condition of employee name to the query condition.

It should be noted that StringUtilsclasses can have different implementations, and which implementation to use depends on the libraries and versions introduced in the project.

Code Explanation 2

The above code is a simple Spring Boot application for paging query of employee information. Its function is to receive three parameters: the current query page number page, the number of records displayed on each page pageSize and employee name, and return a successful response PageInfo object.

Here is a detailed explanation of the code:

  1. @GetMapping("/page")The annotation specifies that the request path is /page, which is mapped to pagethe method.
  2. log.info("page = {},pageSize = {},name = {}" ,page,pageSize,name)In the method, log.infothe method is used to output the values ​​of three parameters, which are the current query page number page, the number of records displayed on each page pageSize, and the employee name.
  3. Page pageInfo = new Page(page,pageSize)A PageInfo object pageInfo is created, which is used to encapsulate paging information and query conditions. Among them, pagethe parameter specifies the current query page number, and pageSizethe parameter specifies the number of records displayed on each page.
  4. LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper()A LambdaQueryWrapper object queryWrapper is created, which is used to encapsulate query conditions. Among them, Employeeis the generic type of the employee information class, and namethe parameter specifies the name of the employee to be queried.
  5. queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name)Added a filter that does fuzzy matching on employee names. Among them, StringUtils.isNotEmpty(name)the method checks whether the name parameter is not empty, and Employee::getNamethe method refers to the class method getName of the employee information, which is used to return the employee name.
  6. queryWrapper.orderByDesc(Employee::getUpdateTime)Added a sorting condition, that is, sorting in descending order by employee update time.
  7. employeeService.page(pageInfo,queryWrapper)The page method of employeeService is called, which receives two parameters: pageInfo object and LambdaQueryWrapper object. The pageInfo object is used to encapsulate paging information and query conditions, and the LambdaQueryWrapper object is used to encapsulate query conditions.
  8. return R.success(pageInfo)A successful response object R is returned, which contains paging information and query results.

To sum up, the above code implements a simple employee information paging query function, receiving three parameters: the current query page number page, the number of records displayed on each page pageSize and employee name, and returns a successful response PageInfo object.

Code Explanation 3

The above code is an employee information paging query API interface in a Java SpringBoot project, which is mainly used to query the list of employees who meet the specified conditions and display them in paging. The specific explanation is as follows:

  1. The @GetMapping(“/page”) annotation indicates that this interface handles GET requests and registers the path mapping of /page.
  2. The three parameters page, pageSize and name respectively represent the current query page number, the number of records displayed on each page and the employee name (optional), and these parameters will be passed in as the request parameters of the interface.
  3. Page pageInfo = new Page(page, pageSize) Assign a value to the pageInfo object, page is the current page number, pageSize is the number of records displayed on each page, this line of code constructs a page constructor object and passes in these two parameters, and then assigns it Give pageInfo.
  4. LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() Constructs a condition constructor for building SQL query statements.
  5. queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name) Add a conditional filter to queryWrapper, if name is not empty, query the employee data whose name contains name. Among them Employee::getName, means to use the getName method of the Employee entity class to perform filtering operations.
  6. queryWrapper.orderByDesc(Employee::getUpdateTime) Adds sorting conditions to queryWrapper, sorting employees in descending order according to their update time. Where Employee::getUpdateTimemeans to use the getUpdateTime method of the Employee entity class for sorting operations.
  7. employeeService.page(pageInfo,queryWrapper) Execute the query, store the query result in the pageInfo object, and finally return pageInfo.
  8. Finally, the interface returns an R class object, using the success method to encapsulate pageInfo into the response body. R is a general response class that encapsulates information such as data and status of the interface response.

3.4 Functional test

After the code is written, we need to restart the project. After the completion, directly visit the homepage of the management system, and the list page of employee management will be opened by default. We can check whether the list data can be displayed normally, or test the paging function through the paging plug-in, and Fuzzy query function of employee name.

When testing, you can use the browser's monitoring tool to view the data interaction details between the page and the server. And with the help of debug, according to the server parameter reception and logic execution.

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-kgoO7taS-1688460908094)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304021805171.png)]

During the test, it can be found that for the employee status field (status), the server returns a status code (1 or 0), but the page displays "normal" or "disabled", because the page is displaying data was processed.

image-20210730010606005

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-RQTKX90k-1688460908095)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131541053.png)]

F8 twice

image-20230606091116014

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-XIHfXtYv-1688460908095)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131541021.png)]

image-20230606091238699

3 times F8

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (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

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-hbaplbux-1688460908097)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131541028.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-GTIWVIAb-1688460908097)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131541445.png)]

image-20230606091640224

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-Dsma9Jn4-1688460908098)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131542324.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-3aifa4Pi-1688460908099)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131542565.png)]

image-20230606092639214

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-pB8Y46cJ-1688460908100)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131542584.png)]

image-20230606092923413

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-9PS8Gm5r-1688460908100)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131542621.png)]

4. Enabling/disabling employee accounts

4.1 Demand Analysis

On the employee management list page, you can enable or disable an employee account . Employees whose accounts are disabled cannot log in to the system, and employees whose accounts are enabled can log in normally. If the status of an employee account is normal, the button is displayed as "Disabled", and if the status of the employee account is disabled, the button is displayed as "Enabled".

It should be noted that only the administrator (admin user) can enable and disable other ordinary users, so the enable and disable buttons are not displayed after ordinary users log in to the system.

A. admin administrator login

image-20210730010858705

B. Ordinary user login

image-20210730010941399

4.2 Program Execution Flow

4.2.1 Dynamic display of page buttons

In the above requirements, we mentioned that the effect that needs to be achieved is: only administrators (admin users) can enable and disable other ordinary users, so after ordinary users log in to the system, the enable and disable buttons are not displayed . How is it displayed on the page? So that only the administrator admin can see the enable and disable buttons?

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-QAWJruTQ-1688460908101)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131543430.png)]

1). When the list page (list.html) is loaded, the hook function created is triggered. In the hook function, the user login information will be obtained from localStorage, and then the user name will be obtained

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-wo8yecOq-1688460908101)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131543117.png)]

After getting it, give the model data user

image-20210730012044171

After getting the model data user, judge through the Vue command v-if. If the logged-in user is admin, the enable/disable button will be displayed, otherwise it will not be displayed.

         </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>

image-20230606162420563

2). In the page, judge through the Vue command v-if, if the login user is admin, the enable/disable button will be displayed, otherwise it will not be displayed

image-20210730012256779

4.2.2 Execution Process Analysis

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-6RBMtaOu-1688460908102)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131543885.png)]

1. The page sends an ajax request and submits the parameters (id, status) to the server

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-SLdGYm2y-1688460908102)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131543443.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-TASciZ0C-1688460908103)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131543717.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-rdDZUSZ8-1688460908103)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131544148.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-wkob9QrV-1688460908103)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131544276.png)]

2. The server Controller receives the data submitted by the page and calls the Service to update the data

3. Service calls Mapper to operate the database

Why clicking the disable or enable button makes a request

1). When the administrator admin clicks the "Enable" or "Disable" button, the method statusHandle is called

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-mUTubERS-1688460908104)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131544669.png)]

image-20210730012723560

scope.row : get the data information of this row;

At the same time, scope.row will be sent out. scope.row is the fully encapsulated JSON object of the data we see.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-pt04BjlQ-1688460908104)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131544852.png)]

2). In the statusHandle method, make a second confirmation, then initiate an ajax request, and pass the id and status parameters

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (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)
              })
            })
          },
image-20210730013011861

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-N3jZsQaM-1688460908105)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131545498.png)]

image-20210730013210948
// 修改---启用禁用接口
function enableOrDisableEmployee (params) {
  return $axios({
    url: '/employee',
    method: 'put',
    data: { ...params }
  })
}

Finally, an asynchronous request is initiated to request the server, and the request information is as follows:

ask illustrate
request method PUT
request path /employee
request parameters {“id”:xxx,“status”:xxx}

{…params} : Three dots is the spread operator that appeared in ES6. The function is to traverse all the properties that the currently used object can access, and put the properties into the current object.

4.3 Code implementation

Before developing the code, you need to sort out the execution process of the entire program:

1). The page sends an ajax request and submits the parameters (id, status) to the server

2). The server Controller receives the data submitted by the page and calls the Service to update the data

3). Service calls Mapper to operate the database

    /**
     * 根据id修改员工信息
     * @param employee
     * @return
     */
    @PutMapping
    public R<String> update(@RequestBody Employee employee){
        
        log.info(employee.toString());

        return null;
    }

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-FNxCuOsq-1688460908106)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131545374.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-ZHK4wg1i-1688460908106)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131550246.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-tiOF9DeG-1688460908107)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131550257.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-oms8Xy8O-1688460908107)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131550686.png)]

Enabling and disabling employee accounts is essentially an update operation, that is, an operation on the status field. Create an update method in the Controller, which is a general method for modifying employee information.

/**
 * 根据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("员工信息修改成功");
}

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-BYsdqUYa-1688460908108)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131550918.png)]

code explanation 1

The above code is a controller method in the Java Spring Boot framework. The code uses @PutMappingannotations to indicate that this method handles HTTP PUT requests.

request.getSession().getAttribute("employee")The purpose of the method is to modify the employee information based on the provided employee id (via get). The parameters of the method include HttpServletRequestobject and Employeeobject, where HttpServletRequestthe object is used to obtain the employee ID in the current session, and Employeethe object contains the employee information that needs to be updated.

The execution steps of the code are as follows:

  1. First, the logger logprints out employeea string representation of the object so that incoming employee information can be viewed in the log.
  2. By request.getSession().getAttribute("employee")getting the employee ID in the current session, and assigning it to empIda variable.
  3. Use to LocalDateTime.now()get the current time and set it as the update time for employee information.
  4. Will empIdbe set as the update user for employee information.
  5. Call employeeService.updateById(employee)the method to update the employee information corresponding to the employee ID in the database.
  6. Finally, a successful Robject is returned, which contains a message string "Employee information modified successfully".

It should be noted that the representation in the code R<String>returns an object containing the generic Stringas R. RIt may be a custom response object, which contains some fields used to represent the result of the request, such as status code, message, etc. For specific implementation, you may need to check the relevant code in the project.

in detail

The above code is a controller method in the Java Spring Boot framework. The code uses @PutMappingannotations to indicate that this method handles HTTP PUT requests.

request.getSession().getAttribute("employee")The purpose of the method is to modify the employee information based on the provided employee id (via get). The parameters of the method include HttpServletRequestobject and Employeeobject, where HttpServletRequestthe object is used to obtain the employee ID in the current session, and Employeethe object contains the employee information that needs to be updated.

The execution steps of the code are as follows:

  1. First, the logger logprints out employeea string representation of the object so that incoming employee information can be viewed in the log.
  2. By request.getSession().getAttribute("employee")getting the employee ID in the current session, and assigning it to empIda variable.
  3. Use to LocalDateTime.now()get the current time and set it as the update time for employee information.
  4. Will empIdbe set as the update user for employee information.
  5. Call employeeService.updateById(employee)the method to update the employee information corresponding to the employee ID in the database.
  6. Finally, a successful Robject is returned, which contains a message string "Employee information modified successfully".

It should be noted that the representation in the code R<String>returns an object containing the generic Stringas R. RIt may be a custom response object, which contains some fields used to represent the result of the request, such as status code, message, etc. For specific implementation, you may need to check the relevant code in the project.

do not understand the point

There are two parameters of the method: HttpServletRequest object and Employee object. The HttpServletRequest object is used to obtain the employee ID in the current session, and the Employee object contains the employee information that needs to be updated.

I'm very sorry, maybe that part of my explanation wasn't clear enough. I will re-explain the parameters of the method and what they do.

  1. HttpServletRequest object: HttpServletRequest is a class in Java Servlet, which represents the HTTP request issued by the client. In this method, we pass in the HttpServletRequest object as a parameter to get the employee ID in the current session.

    The current session refers to the information about the client kept by the server during the interaction with the client (usually a web browser). Sessions can span multiple HTTP requests and remain active for the duration of the session. Through the HttpServletRequest object, we can obtain information related to the session, such as the attribute value stored in the session.

    In this code, we use request.getSession().getAttribute("employee")to get the value of an attribute named "employee" in the session. The attribute value should be the ID of the currently logged in employee.

  2. Employee object: Employee is a custom class that represents employee information. In this method, we pass the Employee object as a parameter, which contains the employee information that needs to be updated.

    Employee objects typically have multiple attributes such as name, title, salary, and so on. In this code, the Employee object we pass in should contain the employee information that needs to be updated. Through this object, we can get and set various attribute values ​​of employees.

    In the subsequent code of the method, we will use the methods of the Employee object to set the employee's update time and update the user, and then pass it to a updateByIdmethod called to update the employee's information in the database.

Summary: The HttpServletRequest object is used to obtain the employee ID in the current session, and the Employee object contains the employee information that needs to be updated. Through these two parameters, we can obtain the employee ID and updated employee information, and perform corresponding operations, such as recording the update time and updating the user, and then update the database.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-JgNNzjoe-1688460908108)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131550358.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-RLM1JVjA-1688460908109)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131550262.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-DXCcbbtw-1688460908109)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131551383.png)]

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-sL4IpM3U-1688460908110)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131551952.png)]

5 times F8

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-Uci1NjFu-1688460908110)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131551679.png)]

id incorrect update failed

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-5wKFdFBK-1688460908110)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131552765.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-YldLBLMm-1688460908111)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131552126.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-q1Dk3KPi-1688460908111)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131552710.png)]

correct id

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-MUp6sEQQ-1688460908112)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131552901.png)]

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-A0aS3BKK-1688460908112)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131553078.png)]

4.4 Functional test

After the code is written, we need to restart the project. Then visit the front-end page to test "enable" or "disable".

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-Ak6gN6U3-1688460908113)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304021806965.png)]

No error was reported during the test, but the function was not implemented, and the data in the database did not change. But from the logs output by the console, it can be seen that the update was not successful.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-xe7AtMoR-1688460908113)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304021806475.png)]

In our database table structure, this ID does not exist, and the ID corresponding to Feng Qingyang in the database is 1420038345634918401

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-GTPRcVIU-1688460908113)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304021806756.png)]

4.5 Code fixes

4.5.1 Cause Analysis

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-GcJSgHbQ-1688460908114)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304021806412.png)]

By observing the SQL output from the console, it is found that the value of the employee id passed on the page is inconsistent with the id value in the database. What is going on?

During pagination query, the server will serialize the returned R object into json format and convert it into data in json format. The ID of the employee is a Long type data, and it is a long integer data with a length of 19 digits. There is no problem with data being returned to the front end.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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对象, 是通过jackson来实现的, 涉及到SpringMVC中的一个消息转换器MappingJackson2HttpMessageConverter, 所以我们要解决这个问题, 就需要对该消息转换器的功能进行拓展。

具体实现步骤:

1). 提供对象转换器JacksonObjectMapper,基于Jackson进行Java对象到json数据的转换(资料中已经提供,直接复制到项目中使用)

2). Extend the message converter of Spring mvc in the WebMvcConfig configuration class, and use the provided object converter in this message converter to convert Java objects to json data

1). Introduce 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);
    }
}

The custom object converter mainly specifies how to process LocalDateTime, LocalDate, and LocalTime when serializing and deserializing json data, and convert BigInteger and Long type data directly into strings.

2). Override the method extendMessageConverters in WebMvcConfig

/**
 * 扩展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);
}

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-teHTLONy-1688460908115)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131553415.png)]

test

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-MQ5BLdhK-1688460908115)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131553663.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-HDAo2cCe-1688460908116)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131553038.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-l8pLvPDF-1688460908116)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131553871.png)]

4 times F8

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-PQunt52v-1688460908119)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131554063.png)]

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-4ycAP3ya-1688460908119)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131554799.png)]

let go

Restart

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-QPWiuaow-1688460908119)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131554310.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-BN09ZbqH-1688460908120)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131554974.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-mDQQgjAk-1688460908120)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131554126.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-R0ztbrd4-1688460908121)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131554438.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-m8x4w378-1688460908121)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131554302.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-qYhpXRqz-1688460908122)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131555469.png)]

5. Edit employee information

Before developing the code, it is necessary to sort out the operation process and the execution process of the corresponding program:
1. When the edit button is clicked, the page jumps to add.html, and the parameter [employee id] is carried in the url
2. Get it on the add.html page The parameter [employee id] in the url
3. Send an ajax request, request the server, and submit the employee id parameter at the same time
4. The server receives the request, queries the employee information according to the employee id, and responds to the page with the employee information in the form of json
5. The page receives The json data responded by the server is echoed with the employee information through VUE data binding.
6. Click the save button, send an ajax request, and submit the employee information on the page to the server in json form.
7. The server receives the employee information, and Perform processing, and respond to the page after completion.
8. After receiving the response information from the server, the page performs corresponding processing

Note: the add.html page is a public page, and both adding and editing employees are performed on this page

1. When the edit button is clicked, the page jumps to add.html and carries the parameter [employee id] in the url

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-erMUGilk-1688460908122)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131555057.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-sEcqqWv7-1688460908123)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306142117010.png)]

2. Obtain the parameter [employee id] in the url on the add.html page

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-eSfqYXtW-1688460908123)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131555202.png)]

3. Send an ajax request, request the server, and submit the employee id parameter at the same time
4. The server receives the request, queries the employee information according to the employee id, and responds to the page with the employee information in the form of json

5. The page receives the json data responded by the server, and echoes the employee information through the data binding of VUE

The reported 404 we just saw uses this id as part of the request path

why send request

Because after receiving the request, our server can query the user according to the id and then echo it to the page and respond to the page in the form of JSON

The page receives the json data responded by the server, and echoes the employee information through VUE's data binding

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-KztVmtZU-1688460908124)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131555540.png)]

important point:

There are two interactions with the server during the modification process

Send the request for the first time to query the corresponding data for echo

The second time when we click the save button, submit our modified data to our server

5.1 Requirements Analysis

Click the "Edit" button on the employee management list page to jump to the edit page, echo the employee information on the edit page and modify it, and finally click the "Save" button to complete the edit operation.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-pwxDABQA-1688460908124)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304021807123.png)]

Then from the above analysis, we can see that the editing function currently implemented, we need to implement two methods:

A. Query based on ID, used for page data echo

B. Save changes

Execution Process (Video Version)

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-8b9eh6MQ-1688460908125)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131555348.png)]

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-XNx1qGS7-1688460908125)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131555106.png)]

5.2 Program Execution Flow

Before developing the code, you need to sort out the operation process and the execution process of the corresponding program:

1). When the edit button is clicked, the page jumps to add.html and carries the parameter [employee id] in the url

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-Ov7g9NOn-1688460908126)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304021807323.png)]

2). Get the parameter [employee id] in the url on the add.html page

3). Send an ajax request, request the server, and submit the employee id parameter at the same time

4). The server receives the request, queries the employee information according to the employee id, and responds the employee information to the page in the form of json

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-0BULTI6z-1688460908126)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202304021807595.png)]

5). The page receives the json data responded by the server, and echoes the employee information through the data binding of VUE

6). Click the save button, send an ajax request, and submit the employee information on the page to the server in json format

7). The server receives employee information, processes it, and responds to the page after completion

8). After receiving the response information from the server, the page performs corresponding processing

image-20210730230533123

Note: the add.html page is a public page, and both adding and editing employees are performed on this page

5.3 Code implementation

5.3.1 Query by ID

After the above analysis, we can see that when querying employee information based on ID, the requested information is as follows:

ask illustrate
request method GET
request path /employee/{id}

Code:

Add a method in EmployeeController to query employee information based on ID.

/**
 * 根据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("没有查询到对应员工信息");
}

code explanation

Explanation 1

The above code is a Java code fragment based on the Spring framework, which is used to implement a RESTful API interface. The code contains a GET request method for querying employee information based on employee ID.

The explanation is as follows:

  1. @GetMapping("/{id}"): This is an annotation that specifies the URL path of the HTTP GET request. /{id}Indicates that the path needs to contain a path parameter named id.
  2. public R<Employee> getById(@PathVariable Long id): This is a public method with return type R. R is a custom response object used to encapsulate the return result of the API interface. The method is named getById and receives a path parameter named id.
  3. log.info("根据id查询员工信息..."): This is a log output statement, which is used to record a message in the log, indicating that the operation of querying employee information based on employee ID is being performed.
  4. Employee employee = employeeService.getById(id): This is to call the getById method of a service object named employeeService, and pass in the id parameter to query employee information based on employee ID. The query result will be saved in the employee object.
  5. if(employee != null): If the employee information is queried (employee is not null), execute the next line of code; otherwise, execute the logic that returns an error message.
  6. return R.success(employee): If the employee information is queried, use the employee information as the data of the successful response, use the R.success method to encapsulate the response result, and then return.
  7. return R.error("没有查询到对应员工信息"): If no employee information is found, use the error information as the data of the error response, use the R.error method to encapsulate the response result, and then return.

In general, this code implements a GET request interface, which queries the corresponding employee information by passing in the employee ID, and returns the query result after being encapsulated in a custom response object R.

Explanation 2

When the client sends a GET request to the specified URL path (for example: /{id}), this method will be executed. In this URL path, we expect to include a path parameter named id in order to specify the ID of the employee being queried.

Inside the method body, first record the operation being executed through the log output, that is, query the employee information according to the employee ID.

Then, obtain the corresponding employee information by calling the getById method of a service object named employeeService and using the incoming id parameter as the query condition. The query results will be saved in an object named employee.

Next, judge whether the employee information is successfully queried by judging whether the employee object is null. If employee is not null, it means that the query is successful, and the employee information is used as the successful response data. The code uses the R.success method to encapsulate the response result into a successful response object R and return it to the client.

If employee is null, it means that no corresponding employee information has been queried. The code uses the R.error method to encapsulate the error information into an error response object R and return it to the client.

In short, this code fragment implements a GET request interface, and the client queries the corresponding employee information by passing the employee ID. If the query is successful, return a successful response containing employee information; if the query fails, return an error response containing error information.

Explain in detail Employee employee = employeeService.getById(id); This is not very clear, can you explain it in detail

When the code reaches Employee employee = employeeService.getById(id);this line, it calls the method employeeServiceof the service object named getById, passing idthe parameters.

In the code, employeeServiceit is a service object that encapsulates employee-related operations. By calling the method, it will query the corresponding employee information getByIdaccording to the parameters passed in .id

The methods here getByIdmay include database query operations or other data acquisition logic, and the specific implementation depends on the employeeServicespecific implementation of the object. It will query the database or other data sources according to the parameters passed in idto obtain the corresponding idemployee information.

The query results will be stored in an object employeenamed Employee. This object will contain the queried employee information such as name, position, salary, etc.

Finally, employeethe object will be used for subsequent judgment and processing. According to the query result, the code will decide to return a successful response (containing employeethe object as the response data) or return an error response (indicating that the corresponding employee information is not queried).

All in all, Employee employee = employeeService.getById(id);the function of this line of code is to call the method of the service object to obtain the corresponding idemployee information, and store the query result in employeethe object named for subsequent processing and returning a response.

employeeServiceis a service object that handles employee information. getByIdThe method is a function in the service object, and its function is to obtain the corresponding employee information according to the incoming employee ID.

In the code, through employeeService.getById(id)this line, the program will call getByIdthe method and pass it in idas a parameter. This way, getByIdthe method knows which employee to query for information.

getByIdidThe method will look up the corresponding employee information in the database or other data sources according to the provided . The result of the query will be assigned to a employeevariable called , which is an Employeeobject of type.

Finally, depending on the condition of the query results, the code decides to return a success response or an error response. If the employee information is successfully found, employeethe data is returned as a successful response. If no corresponding employee information is found, an error message will be returned.

employeeServiceTo put it simply, the purpose of this code is to obtain the information of the corresponding employee by calling the method according to the incoming employee ID getById, and return the corresponding response according to the query result.

Employee employee = employeeService.getById(id);Represents an object instance for obtaining employee information.

employeeServiceIt is a dependency injected Bean, which implements EmployeeServicethe interface, which defines getByIdthe method, the method's parameters are id, and the return value is Employeethe object.

getByIdidThe implementation of the method is to obtain the object instance of the employee information by calling the field of the employee information stored in the database . If the employee information in the database idmatches the value passed in, return the object instance of the employee information, otherwise return null.

Since this interface is defined as a RESTful API, the returned employee information object instance should follow the HTTP response status code and response header specifications. Typically, the response status code is 200 (success) or 404 (resource not found).

In the above code, if the employee information is not empty, a response object is returned R.success(employee), indicating that the employee information has been successfully queried; otherwise, an error response is returned R.error("没有查询到对应员工信息"), indicating that the employee information cannot be queried.

test

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-4LVFSx7e-1688460908127)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131556298.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-pbVuRtMA-1688460908127)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131557745.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-yhWf808k-1688460908127)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131557489.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-ULIpWPwr-1688460908128)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131557465.png)]

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-vyjNO7Bc-1688460908128)(https://cdn.jsdelivr.net/gh/zyziga/picodemo/takeaway/day02 /202306131557210.png)]

5.3.2 Modify Employee

After the above analysis, we can see that when modifying employee information, the requested information is as follows:

ask illustrate
request method PUT
request path /employee
request parameters {…} json format data

Code:

Add a method in EmployeeController to update employee information based on ID.

/**
 * 根据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 Functional test

After the code is written, we need to restart the project. Then visit the front-end page and test according to the operation process analyzed above to check whether the data is modified normally.

Guess you like

Origin blog.csdn.net/m0_59281987/article/details/131538756