瑞吉外卖总体来说挺简单的(crud部分), 但是用了一些以前没用过的技术和技巧, 所以做完之后做个复盘, 避免遗忘

员工后台部分

登录控制

使用 过滤器 接管全部的请求, 确保只有已登录用户才可以使用功能

@WebFilter(filterName = "LoginCheckFilter", urlPatterns = "/*")//这个注解就可以起到接管所有请求的作用
public class LoginCheckFilter implements Filter {

定义出不需要过滤器管理的路径(一般是静态资源和登录要用的东西)

        //2. 定义不需要不需要过滤的请求
        String[] uris = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**",
                "/common/**",
                "/user/sendMsg",//移动端发送邮件
                "/user/login"//移动端登录
        };

使用springframework中自带的路径比较器检查有没有匹配上路径

public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

//使用方法
PATH_MATCHER.match(url, requestURI)//会返回一个布尔值

当员工登录的时候, 在后端需要存入对应session

        HttpSession session = request.getSession();
        session.setAttribute("employee", emp.getId());

这样就可以通过检查当前客户端在后端对应的session是否存在, 判断员工是否登录了!

request.getSession().getAttribute("employee") != null即为已经登录

综上所述, 只要符合 访问的是白名单 或者 已经登录 , 都可以放行

filterChain.doFilter(request, response);

反之返回未登录的json, 这里又涉及到一个知识点:阿里巴巴的fastjson

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>
JSON.toJSONString(R.error("NOTLOGIN")//这样可以生成一个json字符串

扩展json消息转换器

要扩展mvc框架的消息转换器, 我们需要在springMVC的配置类中重写extendMessageConverters方法:

  1. 创建消息转换器对象
  2. 把创建出来的消息转换器的对象转换器设置成jackson
  3. 把自己创建出来的消息转换器对象添加到mvc框架自带的转换器集合, 优先度设置为0
    实操代码:
@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    /**
     * 扩展mvc框架的消息转换器
     * @param converters
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器, 底层使用Jackson转换Java对象到json
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        //添加到mvc自带的转换器集合, 并且设置为T0
        converters.add(0, messageConverter);
    }

}

JacksonObjectMapper 的代码如下:

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