瑞吉外卖项目 基于spring Boot+mybatis

您所在的位置:网站首页 项目背景介绍完整版怎么写好 瑞吉外卖项目 基于spring Boot+mybatis

瑞吉外卖项目 基于spring Boot+mybatis

2024-07-11 17:10:10| 来源: 网络整理| 查看: 265

本项目是基于自学b站中 黑马程序员 的瑞吉外卖项目:视频链接:

黑马程序员Java项目实战《瑞吉外卖》,轻松掌握springboot + mybatis plus开发核心技术的真java实战项目_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV13a411q753?spm_id_from=333.337.search-card.all.click这篇博客是记录自己学习该项目的markdown笔记;并且自己把视频中一些没实现的功能给实现了;本人技术可能不到位,笔记仅供参考学习使用;

本人自己把视频中老师没讲的一些功能给实现了,比如,后台按条件查询客户订单,用户个人查询自己的订单,菜品,套餐的启售,停售,购物车中菜品或者是套餐数量减少,后台套餐的修改。代码不一定规范,但是功能是没问题的!!!

项目中的资料下载链接:(从黑马公众号获取到的最初状态的源码,后面自己补充了一些课程没讲的功能,功能的实现代码在我博客的笔记中有)

链接:https://pan.baidu.com/s/1cdHI5cDjyHKZ4_0GmIevnQ  提取码:668a

目录

一、项目背景介绍 

二、软件开发整体介绍

三、开发环境的搭建

①数据库环境的搭建

②maven项目搭建

③导入前端文件

四、后台登陆功能开发

①需求分析:

②代码开发:

实体类和mapper的开发

service

封装返回的结果类

controller

③功能测试:

五、后台系统退出功能

六、员工管理模块

完善登陆功能

新增员工

全局异常捕获

员工信息分页查询

启用/禁用员工账号

使用自定义消息转换器

编辑员工信息

七、菜品分类管理

公共字段填充(这里有重点)

新增分类

菜品类的分页

删除分类(这里有注意点)

修改分类

八、菜品管理的业务功能

文件的上传和下载(重点)

新增菜品(业务的实现是重点)

接收页面提交的数据(涉及两张表)

菜品信息分页查询(功能完善里面的代码要熟悉,有集合泛型的转换,对象copy)

修改菜品(回显和保存修改都是两张表)

菜品信息的回显:

保存修改:(重点)

需要自己单独实现的功能

九、套餐管理

添加菜品数据回显

保存添加套餐(理解里面的关系有点困难)

套餐信息分页查询

删除套餐

需要自己单独实现的功能

套餐管理的启售,停售

套餐管理的修改

后台订单展示和查询

手机端开发

一、项目背景介绍 

技术选型:

 

 

二、软件开发整体介绍

三、开发环境的搭建 ①数据库环境的搭建

1.创建数据库:

2.导入表结构,直接运行外部SQL文件;

 

数据表的说明:

序号表名说明1employee员工表2category菜品和套餐分类表3dish菜品表4setmeal套餐表5setmeal_dish套餐菜品关系表6dish_flavor菜品口味关系表7user用表(c端)8address_book地址薄表9shopping_cart购物车表10orders订单表11orders_detail订单明细表

②maven项目搭建

 1.创建一个maven项目

注意:创建maven项目后,一定要检查项目的编码,maven仓库的配置,jdk的配置等;

 2.导入pom文件

4.0.0 org.springframework.boot spring-boot-starter-parent 2.6.6 com.itheima reggie_take_out 1.0-SNAPSHOT 8 8 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-web compile com.baomidou mybatis-plus-boot-starter 3.4.2 org.projectlombok lombok 1.18.20 com.alibaba fastjson 1.2.76 commons-lang commons-lang 2.6 mysql mysql-connector-java runtime com.alibaba druid-spring-boot-starter 1.1.23 org.springframework.boot spring-boot-maven-plugin 2.6.6

 3.创建application.yml文件:

server: port: 8080 spring: application: # 应用的名称,选择性配置 name: reggie_take_out 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: root mybatis-plus: configuration: #在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射 map-underscore-to-camel-case: true # 把SQL的查询的过程输出到控制台 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: ASSIGN_ID

 3.创建Boot程序入口

package com.itheima.reggie; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @author LJM * @create 2022/4/14 */ @Slf4j @SpringBootApplication @ServletComponentScan public class ReggieApplication { public static void main(String[] args) { SpringApplication.run(ReggieApplication.class,args); log.info("项目启动成功..."); } }

4.运行Boot程序,看是否成功;

③导入前端文件

注意前端文件的位置,在Boot项目中,前台默认就只能访问 resource目录下的static和template文件夹下的文件;所以如果要使用这种方式,直接创建一个static目录就行,然后把这些前端资源放在这个static目录下就行;

如果你不想把前端文件放在这两个默认的文件夹下,那么就可以自己定义mvc的支持,这里我们使用的就是这方式;(多学习一种定义的方法,以后自定义映射的时候可以使用)

package com.itheima.reggie.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; /** * @author LJM * @create 2022/4/14 */ @Slf4j @Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { /** * 设置资源映射 * @param registry * 前面表示的是浏览器访问的请求 * 后面表示的是要把请求映射到哪里去 */ @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { log.info("开始进行静态资源映射"); registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/"); registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/"); } }

记得在启动程序加上@ServletComponentScan这个注解,否则这个配置类不会生效;

四、后台登陆功能开发 ①需求分析:

需求分析是通过产品原型来进行的,这个是项目经理负责的;

②代码开发:

前端页面访问地址:http://localhost:8080/backend/page/login/login.html

 查看登陆请求信息:点击登录会发送登录请求:http://localhost:8080/employee/login

我们去后端进行代码开发相关的接口就行;

创建相关的包:

实体类和mapper的开发

在entity导入实体类employee类;

使用mybatis-plus提供的自动生成mapper:

package com.itheima.reggie.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.itheima.reggie.entity.Employee; import org.apache.ibatis.annotations.Mapper; @Mapper public interface EmployeeMapper extends BaseMapper { }

 使用快捷键 Ctrl + f3 就可以看见mybatis-plus 帮我们定义的mapper接口:

service package com.itheima.reggie.service; import com.baomidou.mybatisplus.extension.service.IService; import com.itheima.reggie.entity.Employee; public interface EmployeeService extends IService { } package com.itheima.reggie.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.itheima.reggie.entity.Employee; import com.itheima.reggie.mapper.EmployeeMapper; import org.springframework.stereotype.Service; /** * @author LJM * @create 2022/4/15 */ @Service //这两个泛型一个是实体类对应的mapper,一个是实体类 public class EmployeeServiceImpl extends ServiceImpl implements EmployeeService { }

查看帮我们实现的方法:

封装返回的结果类

创建一个新的包,common,用来存放共同使用的类,把这个返回结果类放入这个公共包;

package com.itheima.reggie.common; import lombok.Data; import java.util.HashMap; import java.util.Map; /** * 通用返回结果类,服务端响应的数据最终都会封装成此对象 * @param */ @Data public class R { private Integer code; //编码:1成功,0和其它数字为失败 private String msg; //错误信息 private T data; //数据 private Map map = new HashMap(); //动态数据 public static R success(T object) { R r = new R(); r.data = object; r.code = 1; return r; } public static R error(String msg) { R r = new R(); r.msg = msg; r.code = 0; return r; } public R add(String key, Object value) { this.map.put(key, value); return this; } }

controller

登陆的具体流程图:在平板上,记得传过来。

先处理业务逻辑,然后再编码!!!

1、将页面提交的密码password进行md5加密处理 2、根据页面提交的用户名username查询数据库 3、如果没有查询到则返回登录失败结果 4、密码比对,如果不一致则返回登录失败结果 5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果 6、登录成功,将员工id存入Session并返回登录成功结果 package com.itheima.reggie.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.itheima.reggie.common.R; import com.itheima.reggie.entity.Employee; import com.itheima.reggie.service.EmployeeService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.DigestUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import java.nio.charset.StandardCharsets; /** * @author LJM * @create 2022/4/15 */ @RestController @Slf4j @RequestMapping("/employee") public class EmployeeController { @Autowired private EmployeeService employeeService; @PostMapping("/login") //使用restful风格开发 public R login(HttpServletRequest request, @RequestBody Employee employee){//接收前端的json数据,这个json数据是在请求体中的 //这里为什么还有接收一个request对象的数据? //登陆成功后,我们需要从请求中获取员工的id,并且把这个id存到session中,这样我们想要获取登陆对象的时候就可以随时获取 //1、将页面提交的密码password进行md5加密处理 String password = employee.getPassword();//从前端用户登录拿到的用户密码 password = DigestUtils.md5DigestAsHex(password.getBytes());//对用户密码进行加密 //2、根据页面提交的用户名username查询数据库 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); queryWrapper.eq(Employee::getUsername,employee.getUsername()); //在设计数据库的时候我们对username使用了唯一索引,所以这里可以使用getOne方法 Employee emp = employeeService.getOne(queryWrapper);//这里的切入Wrapper是什么? //3、如果没有查询到则返回登录失败结果 if (emp == null ){ return R.error("用户不存在"); } //4、密码比对,如果不一致则返回登录失败结果 if (!emp.getPassword().equals(password)){ //emp.getPassword()用户存在后从数据库查询到的密码(加密状态的) 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); } } ③功能测试:

使用debug的形式启动项目,然后在浏览器访问:http://localhost:8080/backend/page/login/login.html

然后打开浏览器的f12,查看具体的请求情况:

在后台查看debug的状态:

 运行成功后:(这个密码是123456),数据存在了浏览器中:这个代码是吧返回的数据保持在浏览器中:

localStorage.setItem('userInfo',JSON.stringify(res.data))

在浏览器我们可以看见,key为userInfo,value为我们返回的数据;

五、后台系统退出功能

点击退出按钮,发送退出的请求:http://localhost:8080/employee/logout

 后端代码处理:

①在controller中创建对应的处理方法来接受前端的请求,请求方式为post;

②清理session中的用户id

③返回结果(前端页面会进行跳转到登录页面)

前端代码,也要把浏览器中的数据给清除;

/** * 退出功能 * ①在controller中创建对应的处理方法来接受前端的请求,请求方式为post; * ②清理session中的用户id * ③返回结果(前端页面会进行跳转到登录页面) * @return */ @PostMapping("/logout") public R logout(HttpServletRequest request){ //清理session中的用户id request.getSession().removeAttribute("employee"); return R.success("退出成功"); }

功能测试:先登陆,然后退出即可;看浏览器中的数据是否会被清除;

六、员工管理模块 完善登陆功能

问题分析:前面的登陆存在一个问题,如果用户不进行登陆,直接访问系统的首页,照样可以正常访问,这种设计是不合理的,我们希望看到的效果是只有完成了登陆后才可以访问系统中的页面,如果没有登陆则跳转到登陆页面;

那么如何实现?

答案就是使用过滤器或者是拦截器,在拦截器或者是过滤器中判断用户是否已经完成了登陆,如果没有登陆则跳转到登陆页面;

代码实现:这里使用的是过滤器;

①创建自定义过滤器LongCheckFilter

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; /** * @author LJM * @create 2022/4/15 * 检查用户是否已经完成登陆 * filterName过滤器名字 * urlPatterns拦截的请求,这里是拦截所有的请求 * */ @WebFilter(filterName = "LongCheckFilter",urlPatterns = "/*") @Slf4j public class LongCheckFilter 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.getRequestURL()); //对请求进行放行 filterChain.doFilter(request,response); } }

②在启动类加上注解@ServletComponentScan

然后先测试一下过滤器能不能生效,具体的逻辑等下再书写;发送请求,看后台能不能打印拦截的信息:

 ③完善过滤器的处理逻辑

 具体逻辑的代码实现:

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; /** * @author LJM * @create 2022/4/15 * 检查用户是否已经完成登陆 * filterName过滤器名字 * urlPatterns拦截的请求,这里是拦截所有的请求 * */ @WebFilter(filterName = "LongCheckFilter",urlPatterns = "/*") @Slf4j public class LongCheckFilter implements Filter { //路径匹配器,支持通配符 public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher(); @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //对请求和响应进行强转,我们需要的是带http的 HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; //1、获取本次请求的URI String requestURL = request.getRequestURI(); //定义不需要处理的请求路径 比如静态资源(静态页面我们不需要拦截,因为此时的静态页面是没有数据的) String[] urls = new String[]{ "/employee/login", "/employee/logout", "/backend/**", "/front/**" }; //做调试用的 //log.info("拦截到请求:{}",requestURL); //2、判断本次请求是否需要处理 boolean check = check(urls, requestURL); //3、如果不需要处理,则直接放行 if(check){ //log.info("本次请求{}不需要处理",requestURL); 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) { //把浏览器发过来的请求和我们定义的不拦截的url做比较,匹配则放行 boolean match = PATH_MATCHER.match(url, requestURI); if(match){ return true; } } return false; } }

功能测试: 发起几个请求看看后台的输出,和能不能访问到资源里面的数据,和能不能跳转,注意,上面的后台日志代码已经被注释,需要在后台看到日志的话,需要把注释去掉;

新增员工

数据模型:

新增员工,其实就是将我们的新增页面录入的员工数据插入到employee表;注意:employee表中对username字段加入了唯一的约束,因为username是员工的登陆账号,必须是唯一的!

employee表中的status字段默认设置为1,表示员工状态可以正常登陆;  

 代码开发:

梳理一下代码执行的流程:

/** * 新增员工 * @param employee * @return */ @PostMapping()//因为请求就是 /employee 在类上已经写了,所以咱俩不用再写了 public R save(HttpServletRequest request,@RequestBody Employee employee){ //对新增的员工设置初始化密码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); //创建人的id,就是当前用户的id(在进行添加操作的id) employee.setUpdateUser(empId);//最后的更新人是谁 //mybatis提供的新增方法 employeeService.save(employee); return R.success("新增员工成功"); }

 功能测试:登陆之后,点击添加,然后确认,然后去数据库看一下新增数据成功没,新增成功,那就表示代码可以执行; 注意:但是因为我们把username设置为唯一索引,所以下次再新增用户的时候,就会出现异常,这个异常是MySQL数据库抛出来的;

解决bug:

全局异常捕获

这个全局异常捕获写在common包下;

package com.itheima.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; /** * @author LJM * @create 2022/4/15 * 全局异常处理 */ @ControllerAdvice(annotations = {RestController.class, Controller.class}) //表示拦截哪些类型的controller注解 @ResponseBody @Slf4j public class GlobalExceptionHandler { /** * 处理SQLIntegrityConstraintViolationException异常的方法 * @return */ @ExceptionHandler(SQLIntegrityConstraintViolationException.class) public R exceptionHandle(SQLIntegrityConstraintViolationException exception){ log.error(exception.getMessage()); //报错记得打日志 if (exception.getMessage().contains("Duplicate entry")){ //获取已经存在的用户名,这里是从报错的异常信息中获取的 String[] split = exception.getMessage().split(" "); String msg = split[2] + "这个用户名已经存在"; return R.error(msg); } return R.error("未知错误"); } }

功能测试:登陆后,添加一个一个已经存在账号名,看前端页面提示的是什么信息,以及看后台是否输出了报错日志;

员工信息分页查询

需求分析:系统中的员工比较多的时候,如果在一个页面中全部展示出来会显得比较乱,不便于查看,所以一般都系统中都会以分页的方式来展示列表数据。

 流程分析:

 Java代码:

//配置mybatis-plus的分页插件 package com.itheima.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; /** * @author LJM * @create 2022/4/15 * 配置mybatis-plus提供的分页插件拦截器 */ @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return mybatisPlusInterceptor; } } /** * 员工信息分页 * @param page 当前页数 * @param pageSize 当前页最多存放数据条数,就是这一页查几条数据 * @param name 根据name查询员工的信息 * @return */ @GetMapping("/page") public R page(int page,int pageSize,String name){ //这里之所以是返回page对象(mybatis-plus的page对象),是因为前端需要这些分页的数据(比如当前页,总页数) //在编写前先测试一下前端传过来的分页数据有没有被我们接受到 //log.info("page = {},pageSize = {},name = {}" ,page,pageSize,name); //构造分页构造器 就是page对象 Page pageInfo = new Page(page,pageSize); //构造条件构造器 就是动态的封装前端传过来的过滤条件 记得加泛型 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); //根据条件查询 注意这里的条件是不为空 queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name); //添加一个排序条件 queryWrapper.orderByDesc(Employee::getUpdateTime); //执行查询 这里不用封装了mybatis-plus帮我们做好了 employeeService.page(pageInfo,queryWrapper); return R.success(pageInfo); }

功能测试:分页的三个时机,①用户登录成功时,分页查询一次 ②用户使用条件查询的时候分页一次 ③跳转页面的时候分页查询一次

启用/禁用员工账号

需求分析:

在员工管理列表页面中,可以对某个员工账号进行启用或者是禁用操作。账号禁用的员工不能登陆系统,启用后的员工可以正常登陆;

需要注意的是:只有管理员(admin用户)才可以对其他普通用户进行启用操作,禁用操作,所以普通用户登录系统后启用,禁用按钮不显示;

并且如果某个员工账号的状态为正常,则按钮显示为’‘禁用’,如果员工账号状态为已禁用,则按钮显示为“启用”。

普通员工登录系统后,启用,禁用按钮不显示;

代码开发:

注意:这里修改状态码要反着来,因为正常的用户你只能把它设置为禁用;已经禁用的账号你只能把它设置为正常

流程分析:

注意:启用,禁用的员工账号,本质上就是一个更新操作,也就是对status状态字段进行修改操作;

在controller中创建update方法,此方法是一个通用的修改员工信息的方法,因为status也是employee中的一个属性而已;这里使用了动态SQL的功能,根据具体的数据修改对应的字段信息;

/** * 根据id修改员工信息 * @param employee * @return */ @PutMapping public R 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("员工信息修改成功"); }

功能测试:测试的时候我们发现出现了问题,就是我们修改员工的状态,提示信息显示修改成功,但是我们去数据库查验证的时候,发现员工的状态码压根就没有变化,这是为什么呢?

仔细观察id后,我们会发现后台的SQL语句使用的id和数据库中的id是不一样的!

原因是:mybatis-plus对id使用了雪花算法,所以存入数据库中的id是19为长度,但是前端的js只能保证数据的前16位的数据的精度,对我们id后面三位数据进行了四舍五入,所以就出现了精度丢失;就会出现前度传过来的id和数据里面的id不匹配,就没办法正确的修改到我们想要的数据;

当然另一种解决bug的方法是:关闭mybatis-plus的雪花算法来处理ID,我们使用自增ID的策略来往数据库添加id就行;

使用自定义消息转换器

 代码bug修复:

思路:既然js对long型的数据会进行精度丢失,那么我们就对数据进行转型,我们可以在服务端(Java端)给页面响应json格式的数据时进行处理,将long型的数据统一转换为string字符串;

代码实现步骤:

 步骤一:自定义消息转换类

package com.itheima.reggie.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 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); } }

步骤二:在前面的webMvcConfig 配置类中扩展spring mvc 的消息转换器,在此消息转换器中使用spring提供的对象转换器进行Java对象到json数据的转换;

/** * 扩展mvc框架的消息转换器 * @param converters */ @Override protected void extendMessageConverters(List


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭