Note.Ver_2019.9.3(spring boot/阶段总结)

前言

老规矩,先讲技术后说故事~

技术总结

1. Spring boot 静态资源配置

1.1 开发和部署免配置方案(个人)

开发会在 target文件夹下classes/static
打jar包后会在jar同级目录下static

// java
File path = new File(ResourceUtils.getURL("classpath:").getPath());
File upload = new File(path.getAbsolutePath(),strBuilder("static/upload/",type,"/"));
if(!upload.exists()) {
    return upload.mkdirs()?upload.getPath()+"/":null;
}else
    return upload.getPath()+"/";
# yml
resource:
    static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:static/
1.2 配置文件配置(正规写法)
# application.yml
kcVideo:
  upload: E:/static/
@Configuration
public class StaticResourceConfig extends WebMvcConfigurerAdapter {
    @Value("${kcVideo.upload}")
    private String uploadPath;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    	// 处理配置文件中的配置项,规范配置值最后的'/'
        StringBuilder path = new StringBuilder(uploadPath);
        int lastCharIndex = path.length();
        char lastChar = path.charAt(lastCharIndex-1);
        if (lastChar == '\\')
            path.setCharAt(lastCharIndex-1,'/');
        else if (lastChar != '/')
            path.append('/');
        uploadPath = path.toString();
        //针对'/static/**'请求,添加静态文件夹
        registry.addResourceHandler("/static/**").addResourceLocations("file:"+uploadPath);
        //配置文件上传文件夹
        //FileHelper的代码就不贴了
        FileHelper.uploadPath = uploadPath;
        super.addResourceHandlers(registry);
    }
}

2.Spring boot 2.0 配置拦截器

配置拦截器时,体会到了1.x版本和2.x版本的差异性。拦截路径通过写白名单的方式来实现。下面的配置基于2.x版本。
白名单:

# application.yml
spring:
  profiles:
    include: whiteList
# application-whiteList.yml
qaq:
  jwt-path:
    whiteList:
      - /qaqManager/**
      - /index

拦截器:
拦截器可以实现父类中的三个方法及执行顺序:

拦截器preHandle执行
Controller执行
拦截器postHandle执行
View视图渲染
拦截器afterCompletion执行

关于afterConcurrentHandlingStarted方法,是当Controller中有异步请求执行时调用,具体效果也没有试过了。

// UserTokenInterceptor.java
public class UserTokenInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("Authorization");
        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("UTF-8");
        if (token == null){
            JSONObject jsonObject = new JSONObject(ResponseBuilder.noTokenError());
            response.getWriter().write(jsonObject.toJSONString());
            return false;
        } else {
            return TokenUtil.parseToken(token);
        }
    }
}

配置拦截器:
这里有个注意点,注入参数时用的是@ConfigurationProperties注解,@Value注解并不支持复杂数据结构参数的注入。

@Data
@Configuration
@ConfigurationProperties("qaq.jwt-path")
public class QaqWebMvcConfigurer implements WebMvcConfigurer {
    private List<String> whiteList;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new UserTokenInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns(whiteList);
        registry.addInterceptor(new ManagerTokenInterceptor())
                .addPathPatterns("/qaqManager/**")
                .excludePathPatterns("/qaqManager/login");
    }
}

关于配置拦截器,版本间我们可以做个对比:
1.x:
Note.Ver_2019.9.3(spring boot/阶段总结)_第1张图片
2.x:
Note.Ver_2019.9.3(spring boot/阶段总结)_第2张图片

3.Spring boot集成FastJson

由于spring boot 自带是jackson,其与fastjson对比下在一些应用场景下的性能会差上一些,也可以说是fastjson在json编解码转化方面的性能太强了。所以我们通过手动配置用fastjson替换掉jackson。
首先在配置类中打断点,看一下内部原有配置:
Note.Ver_2019.9.3(spring boot/阶段总结)_第3张图片
现在把原有配置中的jaskson替换:

// 先写配置类
// QaqWebMvcConfigurer.java
@Configuration
public class QaqWebMvcConfigurer implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
		// 配置字符集
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);

		// 配置FastJson相关配置项
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(
                SerializerFeature.PrettyFormat //优化json格式的可读性
        );
        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
        // 替换Jackson
        for (int i = 0;i < converters.size();i ++){
            if (converters.get(i) instanceof MappingJackson2HttpMessageConverter)
                converters.set(i,fastJsonHttpMessageConverter);
        }
    }
}

对fastjson特有注解@JSONField进行测试:

// BlogType.java
// lombok插件生成get/set方法,以及全参构造方法
@Data
@AllArgsConstructor
public class BlogType {
    @Id
    private long id;

    @JSONField(serialize = false)
    private String type;

    @JSONField(format = "yyyy-MM-dd HH:mm")
    private Date date;
}
// jsonTestController.java
@RestController
public class jsonTestController {
    @GetMapping("/index")
    public BlogType getTestJson() {
        return new BlogType(1, "小强",new Date());
    }
}

结果:
Note.Ver_2019.9.3(spring boot/阶段总结)_第4张图片

4.枚举类反射构造数据

通过对枚举类的属性进行反射,拿到字段名和对应值来构造返回数据,只是一种思路,没有结合设计原则和设计模式,也跟自己经验比较少的关系,可能有所欠佳,欢迎交流指正!
枚举类:

// RespJsonEnum.java
public enum  RespJsonEnum {
    SUCCESS(200,"请求成功!"),
    ERROR(500,"服务器错误!"),
    NO_TOKEN_ERROR(1001,"无token信息,请登录!"),
    EXPIRED_TOKEN_ERROR(1002,"token信息已过期,请重新登录!");

    private int status;
    private String message;

    RespJsonEnum(int status,String message){
        this.status = status;
        this.message = message;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

构造器:

@Slf4j
public class ResponseBuilder {
    /**
     * 基础json构造器,反射枚举类的字段名和字段值
     *
     * @param theEnum 消息枚举值
     * @return 枚举类 字段名和字段值生成的Map
     */
    private static HashMap<String, Object> buildBaseJson(Enum theEnum) {
        HashMap<String, Object> baseJson = new HashMap<>();
        Class enumClazz = theEnum.getDeclaringClass();
        Field[] fields = enumClazz.getDeclaredFields();
        try {
            for (Field field : fields) {
                if (!Modifier.isStatic(field.getModifiers())) {
                    field.setAccessible(true);
                    String key = field.getName();
                    Object value = field.get(theEnum);
                    baseJson.put(key, value);
                }
            }
        } catch (IllegalAccessException e) {
            log.error("Error:构建基础消息Map时出错:{}", e.toString());
            e.printStackTrace();
        }
        return baseJson;
    }
}

有关枚举类的反射有个注意点,枚举类基于对static final的封装,我们打个断点debug一下便一目了然:
Note.Ver_2019.9.3(spring boot/阶段总结)_第5张图片

阶段总结

不知不觉中,在公司已经实习了一个月了。前几天回了一次学校,这是从学校出来后第一次返校,感受和心情跟以前假期结束后的返校自然是不同的,自次是一次知道会走的返校。看着新一届的新生们眼中带着好奇的目光,脸上带着些许疑惑的彷徨走进校园,我仿佛看到了三年前的自己。匆匆回校,匆匆离别。在学校待了一晚,离开之时正是新生报到的日子,怀着复杂的心情踏出校园的那刻,与新生们的擦肩仿佛是三年时空的错裂,不禁会有些失神。
回校的路是舒适顺利的,和同伴租了车,一路顺风。离开的路却是艰辛和疲惫的,也不知何时习惯了如此,就好像每次回家一样,回家的路总是安心顺利的,听到家乡的方言更是会不自觉的露出笑容。每次离家也总是艰辛和孤独的。也许心里早已把待了三年的学校当成了另一个家,而那帮舍友更是知己。
人总是在路上的,离别也是为了更好的相遇,可能我已经不再属于学校了吧,难免有些感叹~

你可能感兴趣的:(Spring,boot/Vue)