Springboot project: Detailed analysis of the front and back ends of St. Regis takeaway part 1

Part1 Part 1 (this page)

Part Part 2 link

1 Background user login, exit, request interception

1.1 User login

1.1.1 Logical sorting before starting

  • After the front end clicks to log in, the request is sent to the back end. Pay attention to the naming convention of this path: go down from the view parser to the corresponding resource path, and change it to resource.do (the advantage is that it is very convenient when the interceptor configures the interception path )
  • The controller is a response to the front-end request, and the returned things are basically encapsulated into objects and returned back (use the RetObj class to exchange with the front-end, information exchange, for example, if adding an employee fails, you can return the object of this class, and will prompt The information is sent to the foreground to be displayed in a pop-up window), and this object is placed in the public package.
  • The front-end data is directly encapsulated into an object to the controller. Note that the name submitted by the front-end must be consistent with the attribute name of the back-end entity class! Pay attention to add (@RequestBody) to the parameter Employee employee
  • Then generally you want to get the information of the employee who has successfully logged in, save it in the session, pay attention to the method

insert image description here

  • After clicking the login button, the url, method (post), and data form (json) in F12 can be used to write the back-end controller

1.1.2 Front-end code understanding

  • vue main code
methods: {
    
     //方法:
        async handleLogin() {
    
     //点击登入按钮的时候就会调用(去找前面的点击,对应的handleLogin()),async异步操作,关键词用在函数上
          this.$refs.loginForm.validate(async (valid) => {
    
    //进行校验,主要校验表单是不是为空
            if (valid) {
    
    //如果校验通过
              this.loading = true //(显示登入中...)前面有span v-if标签对应着
              let res = await loginApi(this.loginForm) //验证通过后,通过ajax发送请求,请求的路径点击进去修改!res是controller响应回来的结果;await关键子用于async函数当中(await可以得到异步的结果)
              //loginForm 里面放的就是用户名密码。
              if (String(res.code) === '1') {
    
    
                比如说员工emp的实体,放在这个属性上,前端页面能转为json,保存到浏览器中
                localStorage.setItem('userInfo',JSON.stringify(res.data))
                window.location.href= '/backend/index.html'
              } else {
    
    
                //弹窗res的msg属性,之前这里一直报错F12:Uncaught (in promise) TypeError: Cannot set properties of undefined (setting 'type')
                //原因是你自己设置的属性是message不是msg,这里把属性统一改成了msg
                /*
                  vue语法:提示窗口,有点像alert
                  this.$message({
                      message:'保存成功了,我是message',
                      type: 'success'
                  })
                 */
                this.$message.error(res.msg)
                this.loading = false
              }
            }
          })
        }
  • Note that loginApi() and logoutApi() are in a single script file, and the main function is to perform ajax processing!
function loginApi(data) {
    
    
  return $axios({
    
    
    'url': '/employee/backend/page/login/login.do',
    'method': 'post',
    data
  })
}

function logoutApi(){
    
    
  return $axios({
    
    
    'url': '/employee/backend/page/login/logout.do',
    'method': 'post',
  })
}

1.1.3 Backend code

  • The front end sends request parameters to the background in json string format, then the background needs to use ==@RequestBody== to process the requested json format data, and convert the json data into a java object, otherwise springmvc will not be able to parse the result of passing empty parameters
  • If the @ResponseBody annotation is added, the view parser will not be used, and the page will not be returned. The json data currently returned. If not, go to the view parser and return to the page
@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
    
    
    @Autowired
    private EmployeeService employeeService;
    /**
     * 员工登录
     * @param request
     * @param employee
     * @return
     */
    @PostMapping("/login")
    public R<Employee> login(HttpServletRequest request,@RequestBody Employee employee){
    
    
        //是用json字符串格式向后台传请求参数,那么后台需要采用@RequestBody来处理请求的json格式数据,将json数据转换为java对象,否则springmvc就不能解析导致传空参的结果
        //如果加上@ResponseBody注解,就不会走视图解析器,不会返回页面,目前返回的json数据。如果不加,就走视图解析器,返回页面

        //1、将页面提交的密码password进行md5加密处理
        String password = employee.getPassword();
        password = DigestUtils.md5DigestAsHex(password.getBytes());

        //2、根据页面提交的用户名username查询数据库
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Employee::getUsername,employee.getUsername());
        Employee emp = employeeService.getOne(queryWrapper);

        //3、如果没有查询到则返回登录失败结果
        if(emp == null){
    
    
            return R.error("登录失败");
        }

        //4、密码比对,如果不一致则返回登录失败结果
        if(!emp.getPassword().equals(password)){
    
    
            return R.error("登录失败");
        }

        //5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果
        if(emp.getStatus() == 0){
    
    
            return R.error("账号已禁用");
        }

        //6、登录成功,将员工id存入Session并返回登录成功结果
        request.getSession().setAttribute("employee",emp.getId());
        return R.success(emp);
    }
}

1.2 User Logout

  • Find the position of the style corresponding to the front end
    insert image description here

  • Find the corresponding part of the vue code
    insert image description here
    Analysis: here removeItem is to delete the content stored in the front end; the front end shows that the administrator is xxx, using local storage

    const userInfo = window.localStorage.getItem('userInfo')
    if (userInfo) {
      this.userInfo = JSON.parse(userInfo)
    }
    

Press F12 to see, note that userInfo is added in the data model, after successful login, it will be storyge, and then called again in index.html, showing who the administrator is (next to the exit button)
insert image description here

  • Find the corresponding code in logoutApi
function loginApi(data) {
    
    
  return $axios({
    
    
    'url': '/employee/backend/page/login/login.do',
    'method': 'post',
    data
  })
}

function logoutApi(){
    
    
  return $axios({
    
    
    'url': '/employee/backend/page/login/logout.do',
    'method': 'post',
  })
}

  • After modifying the above url and finding the method, you can now write the back-end controller
    (you can also use F12 to see it, because a request will be sent after clicking the button, and you can see the method, url of the request...)
@PostMapping("/employee/backend/page/login/logout.do")
public RetObj<String> logout(HttpServletRequest request){
    
    
    //清理Session中保存的当前登录员工的id
    request.getSession().removeAttribute(Contants.SESSION_USERID);
    //登入成功了,把对应的对象传给前端;这里的obj就是一个String,前端会显示一个弹窗:退出成功!
    return RetObj.success("退出成功!");//retObj.data = obj;
    }
  • Where is the jump to the login page implemented?

RetObj.success("退出成功!")After the controller returns this object, code=1, it is verified below, after the verification is completed, delete the data userInfo of the browser, and complete the jump!
Note: A bug that I have been looking for for a long time: res.code === 1, and many other places, the front end is written as a number for verification, and the "0" and "1" of the attribute string in your RetObj class ", so it has been unable to pass, pay attention to the details.

 methods: {
    
    
   logout() {
    
    
     logoutApi().then((res)=>{
    
    
       if(res.code === 1){
    
    
         localStorage.removeItem('userInfo')
         window.location.href = '/backend/page/login/login.html'
       }
     })
   },

1.3 Intercepting requests

insert image description here
insert image description here
Only requests for data are intercepted. For pages and static resources, you can view them as much as you want, and they should be released.

  • Code implementation:
    configure first
package cn.edu.uestc.ruijitakeout.common.config;

import cn.edu.uestc.ruijitakeout.backend.interceptor.LoginInterceptor;
import cn.edu.uestc.ruijitakeout.common.JacksonObjectMapper.JacksonObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Slf4j
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    
    
	//消息转换器
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    
    
        log.info("拓展消息转换器成功加载");
        //创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器,底层使用Jackson将Java对象转为json
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        //将上面的消息转换器对象追加到mvc框架的转换器集合中
        converters.add(0,messageConverter);
    }
	//拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        //重写方法,添加拦截器方法
        registry.addInterceptor(loginInterceptor())
                //拦截哪些路径
                .addPathPatterns("/**")
                //不拦截路径
                .excludePathPatterns("/employee/backend/page/login/login.do",
                        "/backend/**",
                        "/employee/backend/page/login/logout.do",
                        "/front/**",
                        "/error"
                );
    }

    @Bean
    public LoginInterceptor loginInterceptor(){
    
    
        return new LoginInterceptor();
    }

}

Interceptor:

@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        String uri = request.getRequestURI();
        log.info("当前路径:{}", uri);

        /**
         * HandlerMethod=>Controller中标注@RequestMapping的方法
         *  需要配置静态资源不拦截时,添加这块逻辑  => 前后端分离项目
         *
         */
        // 是我们的conrtoller中的方法,如果不是的话,放行,给加载静态资源
/*        if (!(handler instanceof HandlerMethod)) {
            log.info("是静态资源或非controller中的方法,放行");
            return true;
        }*/
        //通过session判断是否登入
        if (request.getSession().getAttribute(Contants.SESSION_USERID) == null) {
    
    
            //这里应该跳转到登入页面,,如何做?
            //5、如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据
            log.info("用户未登入,通过输出流方式向客户端页面响应数据,打回登入页面");
            response.getWriter().write(JSON.toJSONString(RetObj.error("NOTLOGIN")));//与前端request.js中的代码呼应
            return false;
        } else {
    
    
            log.info("用户已经登入,id={}", request.getSession().getAttribute(Contants.SESSION_USERID));
            return true;
        }
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
    
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
    
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

2 Staff Management

2.1 Index.html page front-end analysis

  • After the login is complete, enter backend/index.html and develop the page
    insert image description here
  • Note that index.html is just a small page on the left (the black part in the picture above), click the menu navigation bar on the left, and jump to the corresponding url. The front end has a default url, and once you enter it, you can jump directly to the corresponding page, which can be modified to baidu, and Baidu's official website will be displayed on the right, and each page on the right is in another directory: /page/…insert image description here
  • Click the menu in index.html, go to the corresponding html, pay attention to the menuHandle() method
    insert image description here
menuHandle(item, goBackFlag) {
    
    
            this.loading = true
            this.menuActived = item.id
            //这里的url就是前面数据部分里写的url,进行了跳转;
            //iframeUrl在前面定义了,会跳到除了导航栏右边的页面,有iframe定义
            this.iframeUrl = item.url
            this.headTitle = item.name
            this.goBackFlag = goBackFlag
            this.closeLoading()
          },

2.2 Add employees

2.2.1 Arranging ideas before starting

  • The following page is displayed after clicking the "Add Employee" button. You can see the front-end logic by yourself, click on the event, and jump.
    The front end has set some checks that cannot be empty, and the following are the fields that need to be entered.
    insert image description here
  • Note: The name of the employee is unique. If the new add employee front-end page repeatedly adds the form with the same name, the bottom layer of the exception is thrown from the database. This problem will be solved below.
  • Basic process
    You can turn on F12 debugging, enter the corresponding information, check the url, method (post), and the method of submitting data (json), these things can be used to write the back-end controller! Instead of spending a lot of time studying the front-end submission process (it should be understood)
    insert image description here

2.2.2 Front-end jump logic

  • Add an employee button to see for yourself, and it is also a click event that jumps. The following is the click event jump that occurs after the employee information is entered. Now let’s go to the corresponding method: submitForm()
    insert image description here
  • submitForm() first checks... Pay attention to addEmployee(params).then(res => {..the understanding of this request ajax method! The following code mainly processes the information returned by the response.
submitForm (formName, st) {
    
    
  this.$refs[formName].validate((valid) => {
    
    
    if (valid) {
    
    
      if (this.actionType === 'add') {
    
    
        const params = {
    
     //把表单数据拿过来封装成json对象,在下面的函数中传给后端
          ...this.ruleForm,
          sex: this.ruleForm.sex === '女' ? '0' : '1'
        }
        //这个方法和前面的登入、退出类似,封装到了一个js文件中,调用ajax方法,url...与F12对应上了
        //页面返回信息后执行回调函数then()里面的逻辑
        addEmployee(params).then(res => {
    
    
          if (res.code === 1) {
    
    
            this.$message.success('员工添加成功!')
            if (!st) {
    
    
              this.goBack()
            } else {
    
    
              this.ruleForm = {
    
    
                username: '',
                'name': '',
                'phone': '',
                // 'password': '',
                // 'rePassword': '',/
                'sex': '男',
                'idNumber': ''
              }
            }
          } else {
    
    
            this.$message.error(res.msg || '操作失败')
          }
        }).catch(err => {
    
    
          this.$message.error('请求出错了:' + err)
        })
  • addEmployee, click to enter corresponding ajax request
// 新增---添加员工
function addEmployee (params) {
    
    
  return $axios({
    
    
    url: '/employee',
    method: 'post',
    data: {
    
     ...params }
  })
}

2.2.3 Backend code writing

package cn.edu.uestc.ruijitakeout.backend.controller.workbench;
@Slf4j
@RestController
public class CRUDEmployeeController {
    
    

    @Resource
    EmployeeService employeeService;

    @PostMapping("/employee/backend/page/member/add.do")
    public RetObj addEmp(@RequestBody Employee employee, HttpServletRequest request){
    
    
        log.info("成功进入到addEmp的controller");
        //需要为employee设置一些前端没提交的字段数据create_time、update_time、create_user、update_user
        //学会使用LocalDateTime
        employee.setCreateTime(LocalDateTime.now());
        employee.setUpdateTime(LocalDateTime.now());
        //设置初始化密码
        employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
        //create_user,从session中拿
        employee.setCreateUser((Long) request.getSession().getAttribute(Contants.SESSION_USERID));
        employee.setUpdateUser((Long) request.getSession().getAttribute(Contants.SESSION_USERID));

        boolean save = employeeService.save(employee);
        return RetObj.success("成功添加员工!");
    }
}

2.2.4 Solve the problem that the user name and other fields are repeated, resulting in the wrong addition to the database

  • The bottom layer of @ControllerAdvice(…) in global exception handling is the agent, which acts as the controller and takes the method in the controller as an aspect.
  • Using the Spring aspect, some controllers, when some exceptions occur, are cut out as an aspect and processed
  • The main idea is to use RetObj to return the information set in the class!

insert image description here

  • The error is reported as follows. The idea is to write a class (global capture is better to reduce code duplication) that handles exceptions specially. For this repeated submission exception, we use RetObj to intercept the repeated field data and send it to the front end as a reminder. If it is another type of error: the prompt message should write: unknown error!
### Cause: java.sql.SQLIntegrityConstraintViolationException: 
Duplicate entry 'admin2' for key 'employee.idx_username'; 
Duplicate entry 'admin2' for key 'employee.idx_username'; 
nested exception is java.sql.SQLIntegrityConstraintViolationException: 
Duplicate entry 'admin2' for key 'employee.idx_username'] with root cause
  • Global exception handling code
@ControllerAdvice(annotations = {
    
    RestController.class, Controller.class})
@ResponseBody //因为一会儿的写的方法,需要返回一个json数据,所以需要写这个注解(否则返回的就是那个对象!!)
@Slf4j
public class GlobalExceptionHandler {
    
    
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public RetObj<String> exceptionHandler(SQLIntegrityConstraintViolationException exception){
    
    
        log.error(exception.getMessage());
        if (exception.getMessage().contains("Duplicate entry")){
    
    
            String[] split = exception.getMessage().split(" ");
            return RetObj.error(split[2] + "已存在!");
        }else {
    
    
            return RetObj.error("未知错误!");
        }
    }    
}

2.2.4 Summary

  • Mainly understand data flow
    insert image description here

2.3 Paging query of employee information

2.3.1 Implementation thinking analysis

insert image description here

The fourth point is to pay attention to how the Controller or other pages are implementedEncapsulated as jsonIs the form retransmission front-end? After all, returnRetObj is returned;
I personally think that it is annotated: @ResponseBody, the composite annotation in the controller contains
@RestController, so when writing other classes, if it involves returning data to the front end, and in the form of json, pay attention to add @ReponseBody

  • In a similar way, first check F12, the url and method submitted by the page, and the parameters submitted by the front end: page, pageSize, so that you can write the back-end code
    insert image description here

2.3.2 Front-end code analysis

  • As soon as the page is opened, the query request will be submitted automatically, mainly through the vue hook function created() (lifecycle function) to achieve
    insert image description here
  • Three data that may be submitted by the front end: page (page, the default is 1), pageSize (the number of entries per page, the default is 10), name (then fuzzy query according to the name, this is also input in an input box on the front end Yes, additional conditions for query, there is a small button (magnifying glass) next to it, click to execute the query)
  • The front-end logic related to fuzzy query is as follows, pay attention to the clearable attribute, execute handleQuery after clicking, and clear the default prompt. Vue's listening component:@keyup.enter.native
<el-input v-model="input" placeholder="请输入员工姓名" style="width: 250px" 
clearable @keyup.enter.native="handleQuery">
  <i
    slot="prefix"
    class="el-input__icon el-icon-search"
    style="cursor: pointer"
    @click="handleQuery"
  ></i>
</el-input>

handlQquery()

  handleQuery() {
    
    
    this.page = 1;//默认值
    this.init();
  },

init()
insert image description here
includes clicking on the number below the pagination bar, and the corresponding jump to the page is also a similar structure

 handleQuery() {
    
    
   this.page = 1;//默认值
   this.init();
 },
  • For paging query, pay attention to what data the front-end needs, such as recode and other data in the Page object, then when writing the back-end code later, you RetObj<Page>must pay attention to the Page type data passed. Specifically: after Page pageInfo = new Page(page,pageSize);the backend executes the conditional query:empService.page(pageInfo,lambdaQueryWrapper)Directly encapsulate the query results into the pageInfo object. The backend parses the json converted from this object, and you can get the recods and other attribute values ​​inside! recodes is the information of each employee queried, and the front-end code is assigned to tableData. counts is the following "a total of xxx data display"

  • Page class

public class Page<T> implements IPage<T> {
    
    
    private static final long serialVersionUID = 8545996863226528798L;
    protected List<T> records;
    protected long total;
    protected long size;
    protected long current;
    protected List<OrderItem> orders;
    protected boolean optimizeCountSql;
    protected boolean searchCount;
    protected boolean optimizeJoinOfCountSql;
    protected String countId;
    protected Long maxLimit;
    ...

insert image description here

  • Further view or modify the url and method corresponding to getMemberList
function getMemberList (params) {
    
    
  return $axios({
    
    
    url: '/employee/backend/page/member/add.do/page',
    method: 'get',
    params
  })
}
  • As for how to display the page, the element-ui component in vue is mainly used, and the information including the default number of items per page is determined. There are also some details, such as the json data returned by the backend originally only has 1 and 0 for the account status, but it shows normal and disabled on the page, which is because the frontend has processed it.
<el-pagination
        class="pageList"
        :page-sizes="[10, 20, 30, 40]"
        :page-size="pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="counts"
        :current-page.sync="page"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      ></el-pagination>

insert image description here

2.3.3 The backend uses the paging plugin of MybatisPlus for paging

  • Three data that may be submitted by the front-end: page (page, the default is 1, the front-end can choose which page to view, and this message will also be sent to the back-end), pageSize (the number of entries per page, the default is 10), name (then fuzzy query based on the name, which is also entered in an input box at the front end, and is used as an additional condition for the query). This means that the backend needs to write paging constructors and conditional constructors. In general, it is actually very simple for the backend,You only need to pass a Page object to the front end, encapsulated as a json object, records correspond to the information of each employee, and the front end will display them in a loop.

  • Configure MP's pagination plugin

/**
 * MP分页插件的配置
 */
@Configuration
public class MybatisPlusConfig {
    
    
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
    
    
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}
  • The backend controller should catch global exceptions if an error is inserted.
@GetMapping("/employee/backend/page/member/page.do")
public RetObj<Page<Employee>> PaginationQuery(int page, int pageSize, String name){
    
    
    log.info("前端数据:page={},pageSize={},name={}",page,pageSize,name);
    Page<Employee> pageInfo = new Page<>(page,pageSize);
    LambdaQueryWrapper<Employee> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper.like(StringUtils.isNotBlank(name),Employee::getName,name)
            .orderByDesc(Employee::getUpdateTime);
    employeeService.page(pageInfo,lambdaQueryWrapper);
    return RetObj.success(pageInfo);
}

2.4 Disable and enable employee accounts

2.4.1 Implementation thinking analysis

  • analysis needs
    insert image description here

Common user's operation column: only editing function, no enabling and disabling function
insert image description here

  • Development ideas, in fact, the main operation status is enough, and the relevant id is set to 0 when disabled, so there are only two parameters for the front end to the back end: id status
    insert image description here
  • You can also reuse this update method when editing! (The idea is that it doesn’t matter what message the controller receives, just use ==@RequestBody to encapsulate it into the Employee object ==, which makes it possible to encapsulate any data into it and realize multiplexing). In addition, if 根据 ID 选择修改boolean updateById(T entity);the The field is not modified, only the non-null field is modified (full embodiment is update)
    insert image description here
  • The problem that arises: when it is disabled, there are two more zeros in the id in the id update statement. Go to check the data of paging query at that time (the result of paging query is the row currently being operated), and find that the id submitted at that time is also normal. The problem is in the precision of js.
    insert image description here
    insert image description here
    solution:
    insert image description here

2.4.2 Front-end code analysis

  • Realize that ordinary users only have the function of "editing" in the operation column, while administrators can "enable" and "disable" other employee accounts. The front end obtains the currently logged in user name through localstorage, and then v-if="user === 'admin'"judges whether to display the button{ { scope.row.status == '1' ? '禁用' : '启用' }}
<el-table-column label="账号状态">
  <template slot-scope="scope">
    {
   
   { String(scope.row.status) === '0' ? '已禁用' : '正常' }}
  </template>
</el-table-column>
<el-table-column
  label="操作"
  width="160"
  align="center"
>
  <template slot-scope="scope">
    <el-button
      type="text"
      size="small"
      class="blueBug"
      @click="addMemberHandle(scope.row.id)"
      :class="{notAdmin:user !== 'admin'}"
    >
      编辑
    </el-button>
    <el-button
      type="text"
      size="small"
      class="delBut non"
      @click="statusHandle(scope.row)"
      v-if="user === 'admin'"
    >
      {
   
   { scope.row.status == '1' ? '禁用' : '启用' }}
    </el-button>
  • The logic after clicking the enable and disable buttons. As in the above code, click the button to trigger the function and pass the parameter statusHandle(scope.row)(scope.row) which is the json object corresponding to the data. Then the enableOrDisableEmployee() method (this method is encapsulated in the js file) sends an ajax request. At this point, the server must write a controller to receive and process this request.
 //状态修改
statusHandle (row) {
    
    
  this.id = row.id
  this.status = row.status
  //$confirm是elementUI提供的方法,用于弹出窗口的
  this.$confirm('确认调整该账号的状态?', '提示', {
    
    
    'confirmButtonText': '确定',
    'cancelButtonText': '取消',
    'type': 'warning'
    }).then(() => {
    
     //confirmButtonText 这个对应的值 ‘确定点击后’,就会指向then后面这个回调函数
      //enableOrDisableEmployee 发请求,三目运算符,当前是0,就传1给后端
    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)
    })
  })
},

2.4.3 Back-end code analysis

  • At the beginning, I wrote the disabled back-end code separately, and later integrated it with the content of the next section of edit, which means that disabling is also considered edit, and some fields (status) are encapsulated into the Employee object, and then updated.
  • Note that update or updateById() only updates fields that are not null. For example, only the status attribute of the Employee object here is 0 or 1, and the others are all null. However, when the update is past, other fields will not change! , only update xxxx set (non-null field)
@PutMapping("/employee/backend/page/member/forbidden.do")
public RetObj<String> forbiddenUser(@RequestBody Employee employee, HttpServletRequest request){
    
    
    log.info("成功进入controller方法,接收到:id={},status={}",employee.getId(),employee.getStatus());

    LambdaUpdateWrapper<Employee> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
    //UPDATE employee SET status=?,update_time=?,update_user=? WHERE (id = ?)
    lambdaUpdateWrapper.set(Employee::getStatus,employee.getStatus())
            //.set(Employee::getUpdateTime,LocalDateTime.now())
            //.set(Employee::getUpdateUser,request.getSession().getAttribute(Contants.SESSION_USERID))
            .eq(Employee::getId,employee.getId());
    boolean res = employeeService.update(lambdaUpdateWrapper);
    log.info("是否成功:{}",res);
    return RetObj.success("成功禁止使用权限");
}

2.5 Edit employee information

2.5.1 Idea Analysis

insert image description here

  • Step analysis: the key is echoing in the fifth step. The page echoes the current user information that needs to be modified (submit the request, find out the information according to the id, and display it on the top), and modify it on this basis
    insert image description here

2.5.2 Front-end analysis

  • Jump to the add page first, and echo it with the id, the mode is modify
<template slot-scope="scope">
  <el-button
    type="text"
    size="small"
    class="blueBug"
    @click="addMemberHandle(scope.row.id)" /><!--把id传过去,按照id查询出默认信息进行回显-->
    :class="{notAdmin:user !== 'admin'}"
  >
// 添加
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)
  }
},
  • Since the modification also jumps to the newly added page for operation, when the vue object is created, the constructor created() is automatically called
created() {
    
     //钩子函数,vue对象创建后,该函数自动执行
  this.id = requestUrlParam('id')
  //三目运算符,如果id有值,this.id= true,则进入edit页面!
  this.actionType = this.id ? 'edit' : 'add'
  if (this.id) {
    
    //如果id有值
    this.init()
  }
},

Where requestUrlParam method

//获取url地址上面的参数
function requestUrlParam(argname){
    
    
  var url = location.href//获取完整的请求url路径
  var arrStr = url.substring(url.indexOf("?")+1).split("&")//解析字符串,动态取出id值,split是防止有多个参数
  for(var i =0;i<arrStr.length;i++)//遍历数组
  {
    
    
      var loc = arrStr[i].indexOf(argname+"=")
      if(loc!=-1){
    
    
          //id=123456...把数字取出来
          return arrStr[i].replace(argname+"=","").replace("?","")
      }
  }
  return ""如果前面的return没执行,那就返回空,什么也不填充
}
  • Query the database, perform echo, modify the form data directly after the echo is completed, and then click the button to save and modify the database
methods: {
    
    
  async init () {
    
    
    queryEmployeeById(this.id).then(res => {
    
    //回调函数
      console.log(res)
      if (String(res.code) === '1') {
    
    
        console.log(res.data)
        this.ruleForm = res.data//回显,这里就要注意,res的data属性要赋一个Emp类型的值
        this.ruleForm.sex = res.data.sex === '0' ? '女' : '男' //数据库那边是0,1
        // this.ruleForm.password = ''
      } else {
    
    
        this.$message.error(res.msg || '操作失败')
      }
    })
  },
  • Save and continue adding that button is only available in pure add mode
 v-if="actionType == 'add'"
 type="primary"
 class="continue"
 @click="submitForm('ruleForm', true)"
>
 保存并继续添加
</el-button>

2.5.3 Backend code writing

  • After clicking the edit button, the backend query information will be echoed
@GetMapping("/employee/backend/page/member/getEmp.do/{id}")
public RetObj<Employee> queryEmpById(@PathVariable Long id){
    
    
    Employee emp = employeeService.getById(id);
    if (emp!=null){
    
    
        return RetObj.success(emp);
    }
    return RetObj.error("未查询到该员工对应的信息");
}
  • Echo the information to the front end. After the user makes the modification, click the save button. Note that the save button here isreused! ! !When saving a new user, PostMapping (url) is used. When editing a user, it corresponds to PutMapping (url). Note that the url can be the same, and different controller methods can be distinguished by Put or Post. Of course, it can be different, because the front end uses actionType to judge whether it is add or edit, and will call different methods respectively.
submitForm (formName, st) {
    
    
   this.$refs[formName].validate((valid) => {
    
    
         if (valid) {
    
    
           if (this.actionType === 'add') {
    
    
             const params = {
    
     //把表单数据拿过来封装成json对象,在下面的函数中传给后端
               ...this.ruleForm,
               sex: this.ruleForm.sex === '女' ? '0' : '1'
             }....
             ....
           else{
    
    
           ....
           }

Here, different urls are used to distinguish. Note that since you are modifying information, you must not only modify the basic personal information on the front end, but also need to set updatetime and updateuser. You should think comprehensively!

@PutMapping("/employee/backend/page/member/edit.do")
public RetObj<String> updateById(@RequestBody Employee emp, HttpServletRequest request){
    
    
    emp.setUpdateTime(LocalDateTime.now());
    Long updaterId = (Long) request.getSession().getAttribute(Contants.SESSION_USERID);
    emp.setUpdateUser(updaterId);
    log.info("修改后的emp:{}",emp.toString());

    boolean b = employeeService.updateById(emp);
    if (b){
    
    
        return RetObj.success("成功修改信息!");
    }else {
    
    
        return RetObj.error("修改失败!");
    }
}

3 Category management business development (see part2) second article

http://t.csdn.cn/QO1iA

Continuously updating...

Guess you like

Origin blog.csdn.net/YiGeiGiaoGiao/article/details/129393565