外卖项目笔记

1.SpringBoot启动报错

错误信息:

org.springframework.core.NestedIOException: 
ASM ClassReader failed to parse class file 
- probably due to a new Java class file version that isn't supported yet

原因:使用了 Spring 不支持的 Java 字节码版本

解决:img

将字节码版本降低,我选择 10 后顺利启动

img


2.MySql报错 ERROR 2003 (HY000)

Can’t connect to MySQL server on ‘localhost’ (10061)

将数据库文件备份好后。

1、首先排除端口被占用导致 Mysql 报错,输入以下命令查看占用 3306 的进程,发现 3306 并没有被占用。

netstat -ano|findstr 3306

2、直接对 MySql 重新初始化,进入 bin 目录(已添加环境变量可直接运行)

net stop mysql  // 先停止 MySql 服务
mysqld --initialize --console  // 初始化 MySql

img

启动 MySql 服务

net start mysql

使用新初始化得到的 root 密码登录 mysql 即可,后续记得修改可记忆的密码。


3.拦截未登录用户访问管理页面

两种方法:

  • 过滤器
  • 拦截器

过滤器:

过滤器类框架

@Slf4j
@WebFilter(filterName = "LoginCheckFilter", urlPatterns = "/*")
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);
    }
}
app 类添加注解
@ServletComponentScan

4.密码加密

String password = "123456";
DigestUtils.md5DigestAsHex(password.getBytes())

5.全局异常捕获

新增用户时需要异常捕获

try {
    employeeService.save(employee);
} catch (Exception ex) {
    R.error("新增失败");
}

而整个项目有很多处需要捕获异常,频繁地使用如上方式,使代码和开发过程变得复杂且重复

编写异常处理类 GlobalExceptionHandler.java

@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
    // 处理 SQL 异常
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex) {
        log.info("捕获到SQL异常");
        log.error(ex.getMessage());

        return R.error("创建失败..666");
    }
}

含有 annotations = {} 中注解的类会被异常处理模块扫描到。这样无论有多少个需要做异常处理的地方,只需要加一句注解即可被扫描到。

不需要自己一个一个写异常处理代码块。


6.列表分页

在员工的 Controller 类里实现分页方法

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

其中 R<page> 使用的泛型对象 page 来自于 MybatisPlus 提供的分页插件,概况如下

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 isSearchCount;
    protected boolean hitCount;
    protected String countId;
    protected Long maxLimit;

    public Page() {
        this.records = Collections.emptyList();
        this.total = 0L;
        this.size = 10L;
        this.current = 1L;
        this.orders = new ArrayList();
        this.optimizeCountSql = true;
        this.isSearchCount = true;
        this.hitCount = false;
    }

    public Page(long current, long size) {
        this(current, size, 0L);
    }

    ···

修改用户信息失败

img

JDBC 报 Update 0 数据没有修改,观察到

img

请求中的用户 ID 和实际数据库中的 ID 不一致

img

原因

ID 使用了 Long 型,而 JS 可以处理的最长位数是 16 位,当前 ID 为 19 位,丢失了精度。

  • 解决方法:

将 ID 使用对象映射器转换为 String 返回给浏览器

  1. common 包中创建 JacksonObjectMapper 类
/**
 * 对象映射器:基于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);
    }
}
  1. 在 MvcConfig 重写 extendMessageConverters() 方法
@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);
}

此时再做请求时,用户 ID 已经转换为字符串形式,不会产生因 Long 型丢失精度导致的 ID 不存在。

img

posted @ 2023-03-01 11:46  李八御  阅读(32)  评论(0)    收藏  举报