IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> springboot实战-瑞吉外卖系统(1) -> 正文阅读

[Java知识库]springboot实战-瑞吉外卖系统(1)

1.搭建数据库环境

创建数据库

导入sql文件

2.Maven项目搭建

导入依赖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.5</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>org.example</groupId>
  <artifactId>reggie</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
  </properties>

  <dependencies>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <scope>compile</scope>
    </dependency>

    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.4.2</version>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.20</version>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.76</version>
    </dependency>

    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>2.6</version>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid-spring-boot-starter</artifactId>
      <version>1.1.23</version>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>2.4.5</version>
      </plugin>
    </plugins>
  </build>
</project>

配置application.yml

server:
  port: 8080
spring:
  application:
    name: reggie
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/reggie?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
      username: root
      password: 128730
mybatis-plus:
  configuration:
    #在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      # 主键生成策略
      id-type: ASSIGN_ID

ReggieApplication 项目启动测试

package com.reggie.takeout;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

3.静态资源导入

设置静态资源访问--映射路径 com.reggie.takeout.config

WebMvcConfig

package com.reggie.takeout.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        log.info("静态资源开始映射...");
        registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
        registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
    }
}

测试是否映射成功

输入localhost:8080:/backend/index.html

4.登录功能以及退出功能

登录功能

登录需求分析

1.将页面提交的密码进行MD5加密
2.根据用户名查数据库(查不到返回结果)
3.比对密码(密码错误返回结果)
4.查询员工状态,员工状态禁用下不可登录
5.登录成功,写入session中,返回结果。

完善项目包结构

实体类 employee

package com.reggie.takeout.pojo;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * @Description 员工表
 * @Author root
 */
@Data
public class Employee{

    private static final long serialVersionUID = 1L;

    private Long id;

    private String username;

    private String name;

    private String password;

    private String phone;

    private String sex;

    private String idNumber;

    private Integer status;

    @TableField(fill = FieldFill.INSERT)
    private String createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String updateTime;

    @TableField(fill = FieldFill.INSERT)
    private Long createUser;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;

}

mapper

package com.reggie.takeout.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.reggie.takeout.pojo.Employee;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {
}

service和serviceImpl

package com.reggie.takeout.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.reggie.takeout.pojo.Employee;

public interface EmployeeService extends IService<Employee> {
}
package com.reggie.takeout.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.reggie.takeout.mapper.EmployeeMapper;
import com.reggie.takeout.pojo.Employee;
import com.reggie.takeout.service.EmployeeService;
import org.springframework.stereotype.Service;

@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {

}

controller

package com.reggie.takeout.conrtoller;

import com.reggie.takeout.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
    @Autowired
    private EmployeeService employeeService=null;
/**
     * 登录功能
     * @param request
     * @param employee
     * @return
     */
    @PostMapping("/login")
    public R login(HttpServletRequest request, @RequestBody Employee employee){
        //将页面提交的密码进行MD5加密
        String password = employee.getPassword();
        password= DigestUtils.md5DigestAsHex(password.getBytes());
        //根据用户名查数据库(查不到返回结果)
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Employee::getUsername,employee.getUsername());
        Employee emp = employeeService.getOne(queryWrapper);
        //查不到用户名 返回失败
        if (emp==null){
            return R.error("登录失败");
        }
        //比对密码(密码错误返回结果)
        if (!emp.getPassword().equals(password)){
            return R.error("登录失败");
        }
        //查询员工状态,员工状态禁用下不可登录
        if (emp.getStatus()==0){
            return R.error("账户已锁定");
        }
        request.getSession().setAttribute("employee",emp.getId());
        return R.success(emp);
    }
}

?配置返回通用结果类

此类是个通用结果类,服务端响应的所有结果最终都会包装成此种类型返回给前端

package com.reggie.takeout.common;

import lombok.Data;
import java.util.HashMap;
import java.util.Map;


/**
 * 返回通用类
 * @author jekong
 * @date 2022/4/22
 */
@Data
public class R<T> {

    /** 编码:1成功,0和其它数字为失败*/
    private Integer code;

    /** 信息返回*/
    private String msg;

    /** 信息返回数据*/
    private T data;

    /** 动态数据*/
    private Map map = new HashMap();

    public static <T> R<T> success(T object) {
        R<T> r = new R<T>();
        r.data = object;
        r.code = 1;
        return r;
    }

    public static <T> R<T> error(String msg) {
        R r = new R();
        r.msg = msg;
        r.code = 0;
        return r;
    }

    public R<T> add(String key, Object value) {
        this.map.put(key, value);
        return this;
    }

}

退出功能

点击退出?

?退出 移除session

    //退出
    @PostMapping("/logout")
    public R<String> loginOut(HttpServletRequest request){
        request.getSession().removeAttribute("employee");
        return R.success("用户退出成功");
    }

分析

点击登录

 

退出之后 userInfo消失

登录过滤器

步骤:
1.创建自定义过滤器LoginCheckFilter 加入注解@WebFilter
2.在SpringBoot启动类加入注解@ServletComponentScan
3.完善过滤器的处理逻辑
    获取本次处理请求的URL
    判断本次请求是否需要处理
    若不需要,直接放行
    判断登陆状态,若已经登陆直接放行
    若未登陆则返回未登陆结果

LoginCheckFilter

package com.reggie.takeout.filter;

import com.alibaba.fastjson.JSON;
import com.reggie.takeout.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;

@Slf4j
@WebFilter(filterName = "LoginCheckFilter",urlPatterns = "/*")
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;
        //获取本次处理请求的URL
        String requestURI = request.getRequestURI();
        log.info("拦截到请求{}",requestURI);
        //定义不需要处理的请求路径
        String urls[]=new String[]{
          "/employee/login",
          "/employee/logout",
          "/backend/**",
          "/front/**"
        };
        //判断本次请求是否需要处理 方法处理
        boolean check = check(urls, requestURI);
        //若不需要,直接放行
        if (check){
            log.info("本次请求{}不需要处理,直接放行...",requestURI);
            filterChain.doFilter(request,response);
            return;
        }
        //判断登陆状态,若已经登陆直接放行 获取session
        if (request.getSession().getAttribute("employee")!=null){
            log.info("用户已登录,id为..."+request.getSession().getAttribute("employee"));
            filterChain.doFilter(request,response);
            return;
        }
        //若未登陆则返回未登陆结果,通过输出流方式向客户端页面响应数据
        //NOTLOGIN来自于backend/js/request.js 响应拦截器
        log.info("用户未登录...");
        response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
        return;
    }
    /**
     * 
     * @param urls 不需要处理的路径
     * @param requestURL 本次请求的路径
     * @return
     */
    public boolean check(String urls[],String requestURL){
        for (String url:urls){
            boolean match = PATH_MATCHER.match(url, requestURL);
            if (match){
                return true;
            }
        }
        //如果遍历完 没有返回true 证明没有匹配上 返回false
        return false;
    }
}

前端 request.js通过匹配“NOTLOGIN”进行响应 进行页面跳转

5.新增员工

需求:添加员工信息到员工表 用户名username唯一
步骤:
1.页面发送ajax请求,将新增员工页面输入的数据以json的形式提交到服务器
2.服务端Controller接受数据并调用service,Service调用Mapper操作数据库,保存数据
/**
     * 新增员工
     * @param request
     * @param employee
     * @return
     */
    @PostMapping
    public R<String> addEmployee(HttpServletRequest request,@RequestBody Employee employee){
        //设置默认密码 使用md5加密
        employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
        //设置创建时间 更新时间
        employee.setCreateTime(String.valueOf(LocalDateTime.now()));
        employee.setUpdateTime(String.valueOf(LocalDateTime.now()));
        //设置创建者 修改者
        Long userId = (Long) request.getSession().getAttribute("employee");
        employee.setCreateUser(userId);
        employee.setUpdateUser(userId);
        //调用service
        employeeService.save(employee);
        log.info("新增员工信息{}",employee.toString());
       return R.success("添加成功");
    }

全局异常捕获

由于用户名设置了主键唯一,若员工用户名相同就会报错,解决报错有两种方式。

? ? ? ? 1.try catch捕获

? ? ? ? 2.全局的异常捕获

第一种方式后续捕获类似异常需要大量的重复代码,所以使用第二种

GlobalExceptionHandler

package com.reggie.takeout.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 拦截带有RestController Controller注解的类
 * ResponseBody 返回json数据
 */
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 异常处理方法 @ExceptionHandler处理SQLIntegrityConstraintViolationException异常
     * @param exception
     * @return
     */
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public R<String> exceptionHandler(SQLIntegrityConstraintViolationException exception){
        log.info(exception.getMessage());
        //错误信息 Duplicate entry 'guwen' for key 'idx_username'
        if (exception.getMessage().contains("Duplicate entry ")){
            String[] split = exception.getMessage().split(" ");//以空格分隔开
            //Duplicate entry 'guwen' for key 'idx_username'对应
            //0          1       2     3   4        5
            String msg="用户"+split[2]+"已存在";
            return R.error(msg);
        }
        return R.error("未知错误");
    }
}

测试

?6.员工信息展示

分析

?

步骤:
1.页面发送Ajax请求,将分页查询参数(page,pagesize,name)提交到服务端
2.服务端Controller接收页面提交的数据并调用查询的数据
3.Service调用Mapper操作数据库,查询分页数据
4.Controller将查询到的分页数据响应到页面
5.页面接收到分页的数据并通过ElementUI的Table组件展示到页面上

配置Mybatis-plus分页插件

package com.reggie.takeout.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;

@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

controller层

/**
     * 
     * @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);
        //1.构造分页构造器
        Page pageInfo = new Page(page, pageSize);
        //2.构造条件
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.hasText(name),Employee::getName,name);
        //3.添加排序 按照账户创建时间排序
        queryWrapper.orderByAsc(Employee::getCreateTime);
        //4.执行查询
        employeeService.page(pageInfo,queryWrapper);
        return R.success(pageInfo);
    }

启用禁用员工账户

管理员可以对普通用户进行账户启用和禁用,普通用户无相关权限,所以对普通用户不显示启用禁用按钮

页面初始化时获取账户用户名

created() {
          this.init()
          this.user = JSON.parse(localStorage.getItem('userInfo')).username
        },

判断登录账户是否是管理员?

            <el-button
              type="text"
              size="small"
              class="delBut non"
              @click="statusHandle(scope.row)"
              v-if="user === 'admin'"
            >
              {{ scope.row.status == '1' ? '禁用' : '启用' }}
            </el-button>

向后端传递json数据,将要启用禁用的员工id与状态传递给后端

          //状态修改
          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)
              })
            })
          },
// 修改---启用禁用接口
function enableOrDisableEmployee (params) {
  return $axios({
    url: '/employee',
    method: 'put',
    data: { ...params }
  })
}

分析:

1. 页面发送ajax请求,将参数(id、status)提交到服务端
2. 服务端Controller接收页面提交的数据并调用Service更新数据
3. Service调用Mapper操作数据库

?Controller

    /**
     * 根据id修改用户信息
     * @param request
     * @param employee
     * @return
     */
    @PutMapping
    public R<String> update(HttpServletRequest request,@RequestBody Employee employee){//if (String(res.code) === '1') 返回json
        //获取员工id
        Long empId = (Long) request.getSession().getAttribute("employee");
        //更新 修改者和修改时间
        employee.setUpdateUser(empId);
        employee.setUpdateTime(String.valueOf(LocalDateTime.now()));
        //执行修改
        employeeService.updateById(employee);
        return R.success("信息修改成功");
    }

问题:

?数据库中的id与前端传递的id不相同,是因为涉及一个JS的精度问题,JS识别Long类型只精确到16位,而ID有19位,导致ID精度丢失。

代码修复

步骤:
1.使用JacksonObjectMapper对JSON数据进行转换
2.在WebConfig配置类中扩展SringMVC的消息转换器,镜像Java对象到JSON数据的转换

?JacksonObjectMapper

package com.reggie.takeout.common;


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 org.springframework.stereotype.Component;

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]
 */
@Component
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);
    }
}

将id更改为字符串,就不会损失精度,并且修改时间格式?

WebMvcConfig

    /**
     * 扩展MVC消息转化器
     * @param converters
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("扩展消息转换器...");
        //创建消息转换器
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器 底层使用Jackson将java对象转为json
        mappingJackson2HttpMessageConverter.setObjectMapper(new JacksonObjectMapper());
        //将上面的消息转换器对象追加到MVC框架的转换器集合中
        converters.add(0,mappingJackson2HttpMessageConverter);//添加索引,使优先级最高,不然还是会默认使用自带的转换器
    }

7.编辑员工信息

分析:

步骤:
1.点击编辑按钮时,页面跳转到add.html,并在url中携带参数员工ID
2.在add.html页面获取url中的参数员工ID
3.发送ajax请求,请求服务端,同时提交员工id参数
4.服务端接收请求,根据员工id查询员工信息,将员工信息以ison形式响应给页面
5.页面接收服务端响应的ison数据,通过VUE的数据绑定进行员工信息回显
6.点击保存按钮,发送aiax请求,将页面中的员工信息以ison方式提交给服务端
7.服务端接收员工信息,并进行处理,完成后给页面响应
8.页面接收到服务端响应信息后进行相应处理

created() {
          this.id = requestUrlParam('id')
          this.actionType = this.id ? 'edit' : 'add'
          if (this.id) {
            this.init()
          }
        },
//获取url地址上面的参数
function requestUrlParam(argname){
  var url = location.href
  var arrStr = url.substring(url.indexOf("?")+1).split("&")
  for(var i =0;i<arrStr.length;i++)
  {
      var loc = arrStr[i].indexOf(argname+"=")
      if(loc!=-1){
          return arrStr[i].replace(argname+"=","").replace("?","")
      }
  }
  return ""
}
// 修改页面反查详情接口
function queryEmployeeById (id) {
  return $axios({
    url: `/employee/${id}`,
    method: 'get'
  })
}

员工信息回显

Controller

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

由于修改和添加都是共用了add.html页面,所以修改操作只需要根据id查找到员工信息然后回显到前端即可,保存功能复用了上面的update方法

8.公共字段自动填充

新增员工时需要设置时间,创建人,修改时间,修改人等字段,在编辑员工的时候也要设置这些字段,这些属于公共的字段可以使用MybatisPlus提供的公共字段填充功能,避免代码重复

步骤:
1.实体类的属性上加入@TableField注解,指定自动填充的策略
2.按照框架编写元数据对象处理器,同一字段赋值,实现MetaObjectHandler接口
3.使用ThreadLocal解决无法获取session中的员工ID的问题
    3.1编写BaseContext工具类,基于ThreadLocal封装的工具类
    3.2在LoginCheckFilter的doFilter方法中调用BaseContext来设置当前登录用户的id
    3.3在MyMetaObjectHandler的方法中调用BaseContext获取登录用户的id

ThreadLocal

ThreadLocal并不是一个Thread,而是Thread的局部变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
?

我们可以在LogainCheckFilter的doFilter方法中获取当前登录用户id,并调用ThreadLocal的set方法来设置当前线程的线程局部变量的值用户ID,然后使用MyMetaObjectHandler的updateFill方法来获取用户ID

实体类

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @TableField(fill = FieldFill.INSERT)
    private Long createUser;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;

MyMetaObjectHandler?

package com.reggie.takeout.common;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    /**
     * 插入操作自动填充
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("公共字段insert自动填充");
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("createUser",BaseContext.getCurrentId());
        metaObject.setValue("updateUser",BaseContext.getCurrentId());
    }

    /**
     * 更新操作自动填充
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段update自动填充");
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("updateUser",BaseContext.getCurrentId());
    }
}

BaseContext

package com.reggie.takeout.common;

/**
 * 基于ThreadLocal封装工具类,用于保存和获取当前登录用户id
 */
public class BaseContext{
    private static ThreadLocal<Long> threadLocal=new ThreadLocal<Long>();

    public static void setCurrentId(Long id){
        threadLocal.set(id);
    }
    public static Long getCurrentId(){
        return threadLocal.get();
    }
}

CheckLoginFilter

        //判断登陆状态,若已经登陆直接放行 获取session
        if (request.getSession().getAttribute("employee")!=null){
            log.info("用户已登录,id为..."+request.getSession().getAttribute("employee"));
            Long empId=(Long)request.getSession().getAttribute("employee");
            BaseContext.setCurrentId(empId);
            filterChain.doFilter(request,response);
            return;
        }

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-07-04 22:41:24  更:2022-07-04 22:43:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 15:28:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码