spring Boot必用依赖框架

spring Boot必用依赖框架

使用Lombok框架

在编写POJO类型(包括实体类、VO、DTO等)时,都有统一的编码规范,例如:

  • 属性都是私有的
  • 所有属性都有对应的Setter & Getter方法
  • 应该重写`equals()`和`hashCode()`方法,以保证:如果2个对象的字面值完全相同,则`equals()`对比结果为`true`,且`hashCode()`返回值相同,如果2个对象的字面值不相同,则`equals()`对比结果为`false`,且`hashCode()`返回值不同
  • 实现`Serializable`接口
  • 为了便于观察对象的各属性值,通常还会重写`toString()`方法。
  • 由于以上操作方式非常固定,且涉及的代码量虽然不难,但是篇幅较长,并且,当类中的属性需要修改时(包括修改原有属性、或增加新属性、删除原有属性),对应的其它方法都需要修改(或重新生成),管理起来比较麻烦。

    使用Lombok框架可以极大的简化这些操作,此框架可以通过注解的方式,在编译期来生成Setters & Getters、`equals()`、`hashCode()`、`toString()`,甚至生成构造方法等,所以,一旦使用此框架,开发人员就只需要在类中声明各属性、实现`Serializable`、添加Lombok指定的注解即可。

    在Spring Boot中,添加Lombok依赖,可以在创建项目时勾选,也可以后期自行添加,依赖项的代码为:

    //依赖 org.projectlombok lombok true

    完成后,在各POJO类型中,将不再需要在源代码添加Setters & Getters、`equals()`、`hashCode()`、`toString()`这些方法,只需要在POJO类上添加`@Data`注解即可!

    当添加`@Data`注解,且删除相关方法后,由于源代码中没有相关方法,则调用了相关代码的方法可能会报错,但是,并不影响程序运行!

    为了避免IntelliJ IDEA判断失误而提示了警告和错误,推荐安装Lombok插件,可参考:

    小辣椒插件

    【注】:无论是否安装插件,都不影响代码的编写和运行!

    Slf4j日志框架

    在开发实践中,不允许使用`System.out.println()`或类似的输出语句来输出显示关键数据(核心数据、敏感数据等),因为,如果是这样使用,无论是在开发环境,还是测试环境,还是生产环境中,这些输出语句都将输出相关信息,而删除或添加这些输出语句的操作成本比较高,操作可行性低。

    推荐的做法是使用日志框架来输出相关信息!

    当添加了Lombok依赖后,可以在需要使用日志的类上添加`@Slf4j`注解,然后,在类的任意中,均可使用名为`log`的变量,且调用其方法来输出日志(名为`log`的变量也是Lombok框架在编译期自动补充的声明并创建对象)!

    在Slf4j日志框架中,将日志的可显示级别根据其重要程度(严重程度)由低到高分为:

  • – trace:跟踪信息
  • – debug:调试信息
  • – info:一般信息,通常不涉及关键流程和敏感数据
  • – warn:警告信息,通常代码可以运行,但不够完美,或不规范
  • – error:错误信息
  • 在配置文件中,可以通过`logging.level.包名.类名`来设置当前类的日志显示级别,例如:

    // yml文件写法logging: level: cn.celinf.boot.demo: info// .properties文件格式写法logging.level.cn.celinf.boot.demo: info

    当设置了显示的日志级别后,仅显示设置级别和更重要的级别的日志,例如,设置为`info`时,只显示`info`、`warn`、`error`,不会显示`debug`、`trace`级别的日志!

    当输出日志时,通过`log`变量调用`trace()`方法输出的日志就是`trace`级别的,调用`debug()`方法输出的日志就是`debug()`级别的,以此类推,可调用的方法还有`info()`、`warn()`、`error()`。

    在开发实践中,关键数据和敏感数据都应该通过`trace()`或`debug()`进行输出,在开发环境中,可以将日志的显示级别设置为`trace`,则会显示所有日志,当需要交付到生产环境中时,只需要将日志的显示级别调整为`info`即可!

    默认情况下,日志的显示级别是`info`,所以,即使没有在配置文件中进行正确的配置,所有info、warn、error级别的日志都会输出显示。

    • 在配置时,属性名称中的`logging.level`部分是必须的,在其后,必须写至少1级包名
    • 发实践中,属性名称通常配置为`logging.level.项目根包`

    在使用Slf4j时,通过`log`调用的每种级别的方法都被重载了多次(各级别对应除了方法名称不同,重载的次数和参数列表均相同),推荐使用的方法是参数列表为`(String format, Object… arguments)`的,例如:

    public void trace(String format, Object… arguments);public void debug(String format, Object… arguments);public void info(String format, Object… arguments);public void warn(String format, Object… arguments);public void error(String format, Object… arguments);

    以上方法中,第1个参数是将要输出的字符串的模式(模版),在此字符串中,如果需要包含某个变量值,则使用`{}`表示,如果有多个变量值,均是如此,然后,再通过第2个参数(是可变参数)依次表示各`{}`对应的值,例如:

    log.debug(“加密前的密码:{},加密后的密码:{}”, password, encodedPassword);

    使用这种做法,可以避免多变量时频繁的拼接字符串,另外,日志框架会将第1个参数进行缓存,以此提高后续每一次的执行效率。

    在开发实践中,应该对程序执行关键位置添加日志的输出,通常包括:

  • – 每个方法的第1行有效语句,表示代码已经执行到此方法内,或此方法已经被成功调用
  • – 如果方法是有参数的,还应该输出参数的值
  • – 关键数据或核心数据在改变之前和之后
  • – 例如对密码加密时,应该通过日志输出加密前和加密后的密码
  • – 重要的操作执行之前
  • – 例如尝试插入数据之前、修改数据之前,应该通过日志输出相关值
  • – 程序走到某些重要的分支时
  • – 例如经过判断,走向抛出异常之前
  • 其实,Slf4j日志框架只是日志的一种标准,并不是具体的实现(感觉上与Java中的接口有点相似),常见有具体实现了日志功能的框架有log4j、logback等,为了统一标准,所以才出现了Slf4j,同时,由于log4j、logback等框架实现功能并不统一,所以,Slf4j提供了对主流日志框架的兼容,在Spring Boot工程中,`spring-boot-starter`就已经依赖了`spring-boot-starter-logging`,而在此依赖下,通常包括Slf4j、具体的日志框架、Slf4j对具体日志框架的兼容。

    密码加密(额外知识点)

    【这并不是Spring Boot框架的知识点】

    对密码进行加密,可以有效的保障密码安全,即使出现数据库泄密,密码安全也不会受到影响!为了实现此目标,需要在对密码进行加密时,使用不可逆的算法进行处理!

    通常,不可以使用加密算法对密码进行加密码处理,从严格定义上来看,所有的加密算法都是可以逆向运算的,即同时存在加密和解密这2种操作,加密算法只能用于保证传输过程的安全,并不应该用于保证需要存储下来的密码的安全!

    哈希算法都是不可逆的,通常,用于处理密码加密的算法中,典型的是一些消息摘要算法,例如MD5、SHA256或以上位数的算法。

    消息摘要算法的主要特征有:

  • – 消息相同时,摘要一定相同
  • – 某种算法,无论消息长度多少,摘要的长度是固定的
  • – 消息不同时,摘要几乎不会相同
  • 在消息摘要算法中,以MD5为例,其运算结果是一个128位长度的二进制数,通常会转换成十六进制数显示,所以是32位长度的十六进制数,MD5也被称之为128位算法。理论上,会存在2的128次方种类的摘要结果,且对应2的128次方种不同的消息,如果在未超过2的128次方种消息中,存在2个或多个不同的消息对应了相同的摘要,则称之为:发生了碰撞。一个消息摘要算法是否安全,取决其实际的碰撞概率,关于消息摘要算法的破解,也是研究其碰撞概率。

    存在穷举消息和摘要的对应关系,并利用摘要在此对应关系进行查询,从而得知消息的做法,但是,由于MD5是128位算法,全部穷举是不可能实现的,所以,只要原始密码(消息)足够复杂,就不会被收录到所记录的对应关系中去!

    为了进一步提高密码的安全性,在使用消息摘要算法进行处理时,通常还会加盐!盐值可以是任意的字符串,用于与密码一起作为被消息摘要算法运算的数据即可,例如:

    @Component // 实例化到spring容器中public class PasswordEncoder { /** * 加密 * @param rawPassword 源密码 * @return */ public String encode(String rawPassword) { //盐 UUID不重复随机字符串 String salt = UUID.randomUUID().toString().replace(“-“,””); String encodedPassword = DigestUtils.md5DigestAsHex((salt+rawPassword).getBytes()); return salt+encodedPassword; }/** * 密码对比 * @param rawPassword 原密码 * @param encodedPassword 加密的密码 * @return */ public Boolean decode(String rawPassword,String encodedPassword) { //盐 String salt = encodedPassword.substring(0,32); String newPassword = DigestUtils.md5DigestAsHex((salt+rawPassword).getBytes()); //判断是否相等 return newPassword.equals(encodedPassword); }}

    加盐的目的是使得被运算数据变得更加复杂,盐值本身和用法并没有明确要求!

    甚至,在某些用法或算法中,还会使用随机的盐值,则可以使用完全相同的原消息对应的摘要却不同!

    > 推荐了解:预计算的哈希链、彩虹表、雪花算法。

    为了进一步保证密码安全,还可以使用多重加密,即反复调用消息摘要算法。

    除此以外,还可以使用安全系数更高的算法,例如SHA-256是256位算法,SHA-384是384位算法,SHA-512是512位算法。

    Validation框架

    当客户端向服务器提交请求时,如果请求数据出现明显的问题(例如关键数据为`null`、字符串的长度不在可接受范围内、其它格式错误),应该直接响应错误,而不是将明显错误的请求参数传递到Service!

    > 关于判断错误,只有涉及数据库中的数据才能判断出结果的,都由Service进行判断,而基本的格式判断,都由Controller进行判断。

    Validation框架是专门用于解决检查数据基本格式有效性的,最早并不是Spring系列的框架,目前,Spring Boot提供了更好的支持,所以,通常结合在一起使用。

    在Spring Boot项目中,需要添加`spring-boot-starter-validation`依赖项,例如:

    //依赖项 org.springframework.boot spring-boot-starter-validation

    在控制器中,首先,对需要检查数据格式的请求参数添加`@Valid`或`@Validated`注解(这2个注解没有区别),例如:

    @RequestMapping(“/add-new”)public JsonResult addNew(@Validated AdminAddNewDTO adminAddNewDTO) { adminService.addNew(adminAddNewDTO); return JsonResult.ok();}

    真正需要检查的是`AdminAddNewDTO`中各属性的值,所以,接下来需要在此类的各属性上通过注解来配置检查的规则,例如:

    @Datapublic class AdminAddNewDTO implements Serializable {@NotNull // 验证规则为:不允许为nullprivate String username;@NotNullprivate String password;// ===== 原有其它代码 =====}

    重启项目,通过不提交用户名的URL(例如:http://localhost:8080/admins/add-new)进行访问,在浏览器上会出现400错误页面,并且,在IntelliJ IDEA的控制台会出现以下警告:

    //警告2022-06-07 11:37:53.424 WARN [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.validation.BindException:org.springframework.validation.BeanPropertyBindingResult: 1 errorsField error in object ‘adminAddNewDTO’ on field ‘username’: rejected value [null]; codes [NotNull.adminAddNewDTO.username,NotNull.username,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [adminAddNewDTO.username,username]; arguments []; default message [username]]; default message [不能为null]]

    从警告信息中可以看到,当验证失败时(不符合所使用的注解对应的规则时),会出现`org.springframework.validation.BindException`异常,则自行处理此异常即可!

    首先,在`State`中添加新的枚举:

    public enum State {OK(200),ERR_USERNAME(201),ERR_PASSWORD(202),ERR_BAD_REQUEST(400), // 新增ERR_INSERT(500);// ===== 原有其它代码 =====}

    然后,在`GlobalExceptionHandler`中添加新的处理异常的方法:

    @ExceptionHandler(BindException.class)public JsonResult handleBindException(BindException e) {return JsonResult.fail(State.ERR_BAD_REQUEST, e.getMessage());}

    关于错误提示信息,以上内容中出现了`不能为null`的字样,是默认的提示文本,可以通过`@NotNull`注解的`message`属性进行配置,例如:

    @Datapublic class AdminAddNewDTO implements Serializable { @NotNull(message = “添加管理员失败,请提交用户名!”) private String username; @NotNull(message = “添加管理员失败,请提交密码!”) private String password;// ===== 原有其它代码 =====}

    然后,在处理异常时,通过异常信息获取自定义的提示文本:

    @ExceptionHandler(BindException.class)public JsonResult handleBindException(BindException e) {BindingResult bindingResult = e.getBindingResult();String defaultMessage = bindingResult.getFieldError().getDefaultMessage();return JsonResult.fail(State.ERR_BAD_REQUEST, defaultMessage);}

    再次运行,在不提交用户名和密码的情况下,会随机的提示用户名或密码验证失败的提示文本中的某1条。

    在Validation框架中,还有其它许多注解,用于进行不同格式的验证,例如:

  • – `@NotEmpty`:只能添加在`String`类型上,不许为空字符串,例如`””`即视为空字符串
  • – `@NotBlank`:只能添加在`String`类型上,不允许为空白,例如普通的空格可视为空白,使用TAB键输入的内容也是空白,(虽然不太可能在此处出现)换行产生的空白区域也是空白
  • – `@Size`:限制大小
  • – `@Min`:限制最小值
  • – `@Max`:限制最大值
  • – `@Range`:可以配置`min`和`max`属性,同时限制最小值和最大值
  • – `@Pattern`:只能添加在`String`类型上,自行指定正则表达式进行验证
  • – 其它
  • 以上注解,包括`@NotNull`是允许叠加使用的,即允许在同一个参数属性上添加多个注解!

    以上注解均可以配置`message`属性,用于指定验证失败的提示文本。

    通常:(开发中)

  • – 对于必须提交的属性,都会添加`@NotNull`
  • – 对于数值类型的,需要考虑是否添加`@Range`(则不需要使用`@Min`和`@Max`)
  • – 对于字符串类型,都添加`@Pattern`注解进行验证
  • 常用检验注解

    学习记录,如有侵权请联系删除

    郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
    (0)
    用户投稿
    上一篇 2022年6月12日
    下一篇 2022年6月12日

    相关推荐

    联系我们

    联系邮箱:admin#wlmqw.com
    工作时间:周一至周五,10:30-18:30,节假日休息