---
title: 零碎笔记
date: 2022-07-15 +/-TTTT
categories: [生活, 闲聊]
tags: []     # TAG names should always be lowercase
---

# 系统设计
1. 业务往往伴随着参数校验

# 后端与数据库交互
1. 数据库的日期类型是date，后端参数为String时也可以存入，取数据的时候，也可以直接赋值给String，范围查询也可以直接使用日期字符串作为参数，**总结似乎存在一个转换器能自动将String转换成数据库类型Date，和将数据库类型Date转换成String**，同时月或日只有一位时，数据库会自动补零

# 日期的格式化
```java
// SpringBoot提供的日期格式化注解，用于格式化前端发给后端的日期数据
@DateTimeFormat

// jackson提供的注解，用于格式化数据库中提取的日期数据
@JsonFormat

// fastjson提供的注解，兼具上面两个注解的功能
@JSONField
```

目前这三个注解还没测试

# 数据库sql
1. default约束不能使用函数

# Spring邮件服务
1. Spring Boot application.yml邮件服务配置：

![邮件服务配置](/blog/202207192203788.png "Optional title")

# Spring参数校验
1. @Validated和@Valid只会在父方法中生效，在实现方法中覆盖方法的参数校验规则会失败且会报错：`javax.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not redefine the parameter constraint configuration`，所以写参数校验时应该在父方法中定义配置，子类继承就好了，不用修改
2. 在Service中使用参数校验，需要用@Validated和@Valid组合使用，@Validated的作用是：提示Spring为组件开启数据校验功能，相比与@Valid，Validated能为@Controller、@Service、@Component等标注的组件开启数据校验功能、而@Valid只能为Controller组件开启数据校验，但是@Validated不支持嵌套验证
```java
import com.flameking.community.entity.User;
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
/**
 * service接口
 */
@Validated
public interface UserService {

  /**
   * 根据用户id查询用户信息
   * @param id
   * @return 帖子对应的发帖人的信息
   */
  User selectUserById(Integer id);

  /**
   * 注册用户信息
   * @param user
   * @return
   */
  int register(@Valid User user);
}
```
```java
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.util.Date;

@Data
public class User {
    private Integer id;
    @NotBlank
    private String username;
    @NotBlank
    private String password;
    private String salt;
    @NotBlank
    private String email;
    private Integer type;
    private Integer status;
    private String activationCode;
    private String headerUrl;
    private Date createTime;
}
```

# Spring Boot测试配置
1. SpringBoot2.4.x之后，改为默认仅集成JUnit5，干掉了兼容JUnit4，所以如果想使用Junit4可以选择使用低版本的（低版本同时兼容Junit5和Junit4），当然也可以直接引入Junit4的依赖


# Spring Boot数据库配置
2. 数据库配置问题：`java.sql.SQLException: No timezone mapping entry for 'HongKong'`，将其修改为serverTimezone=Asia/Shanghai
3. 数据库serverTimezone配置的不一样可能会使得数据库日期类查询与我们当前时间有差别，比如可能差8个小时，但我们一般设置为serverTimezone=Asia/Shanghai是没有问题的，另外MySQL8.0+版本不写serverTimezone好像会报错，虽然我用的是5.7.33

# Spring Boot Bean的问题
1. IDEA，注入的mapper类总是报错：<br>
![Mapper注入](/blog/202207161747809.png "Mapper注入")

# Spring Boot mybatis配置的问题
type-aliases-package的作用：<br>
![type-aliases-package](/blog/202207161816099.png "type-aliases-package")

# Spring Boot Thymeleaf引擎
1. Thymeleaf命名空间：xmlns:th="http://www.thymeleaf.org"
2. Thymeleaf的公共页面复用：

![复用公共部分](/blog/202207201037527.png "Optional title")

**注意：复用的原理是直接用公共部分替换原来的元素，所以其实原来的元素标签与复用的公共部分标签不同也没问题，样式不同也没问题，因为最后都会替换成公共部分**

# Spring Boot 日志
Spring Boot的默认日志工具是logback，在application.yml中我们可以定义日志：

![日志配置](/blog/202207192117215.png "Optional title")

在application中我们只能对日志进行简单的配置，实际业务需求中我们可能需要：将不同级别的日志放在不同的文件中，每个项目的日志放在项目文件下；要进行这样复杂的配置就需要使用到xml文件：

```xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <contextName>community</contextName>
    <property name="LOG_PATH" value="E:/log/"/>
    <property name="APPDIR" value="community"/> <!--日志最终会被存在D:/work/data/community下-->

    <!-- error file -->
    <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APPDIR}/log_error.log</file>                                        <!--该日志命名为log_error.log-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${APPDIR}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>          <!--新生成日志存放的地址-->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>5MB</maxFileSize>                      <!--日志内容最大不能超过5MB，否则会另外生成新的文件存储-->
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>30</maxHistory>                              <!--日志文件的最大存储期限是30天，超过会自动删除-->
        </rollingPolicy>
        <append>true</append>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>                 <!--日志输出格式-->
            <charset>utf-8</charset>                                                                <!--日志字符集utf-8支持中文-->
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">                                  <!--过滤器-->
            <level>error</level>                                                                    <!--过滤级别是error-->
            <onMatch>ACCEPT</onMatch>                                                               <!--如果配置就接受否则拒绝-->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- warn file -->
    <appender name="FILE_WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APPDIR}/log_warn.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${APPDIR}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>5MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <append>true</append>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- info file -->
    <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APPDIR}/log_info.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${APPDIR}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>5MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <append>true</append>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- console -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
    </appender>

    <logger name="com.flameking.community" level="debug"/>                       <!--com.nowcoder.community包下的日志级别是debug-->

    <root level="info">                                                         <!--整个项目下所有的jar包日志级别是info-->
        <appender-ref ref="FILE_ERROR"/>
        <appender-ref ref="FILE_WARN"/>
        <appender-ref ref="FILE_INFO"/>                                         <!--日志级别从大到小：error、warn、info、debug、trace-->
        <appender-ref ref="STDOUT"/>
    </root>

</configuration>
```

首先这个文件是被Spring Boot自动识别的，我们只需要将其放在resources文件夹下，并将其命名为`logback-spring.xml`，必须这样命名，否则spring boot无法识别

# SpringMVC转发和重定向
1. 我们在使用重定向的时候往往是为了解耦两个不相关的业务，比如登录和注册、删除记录和查询记录
2. 转发关键词：forward，重定向：redirect
3. 两个不同类型的请求互相转发会报错
4. 请求转发后存入model的参数在目标请求的model中是不存在的，此时需要使用@RequestAttribute注解获取对应的参数
5. 请求转发后依然会进入拦截器

# SpringMVC请求注解
1. `@RequestBody`，这个是专门用来接收前端json数据的，这些数据放在请求体中

# SpringMVC接收参数
1. 对于checkbox的输入框，在是否选择时，如果后端使用Boolean类型接收，当没选中时，Boolean接收值总是null，而用boolean就没问题

# SpringMVC拦截器
1. 如果任何一个拦截器的preHandle方法返回false或者抛出异常，或者handler方法中抛出异常都不会执行postHandle方法。

# mybatis，mapper.xml和mapper.java需要注意的问题
使用注解@Param的时机：<br>
1. 在动态SQL中用到了参数作为判断条件，就算SQL对应的的方法有且只有这一个参数，如果不加@Param就会报错
```sql
<select id="getUserById" resultType="com.flameking.community.User">
    select * from user
    <if test="id!=null">
        where id=#{id}
    </if>
</select>
```
```java
@Mapper
public interface UserMapper {
 List<User> getUserById(@Param("id")Integer id);
}
```

2. 需要为参数指定别名
3. 有多个参数时
4. mapper.xml中的SQL使用了\$，那么参数中也需要@Param注解，\$ 会有注入漏洞的问题，但是有的时候你不得不使用\$ 符号，例如要传入列名或者表名的时候，这个时候必须要添加 @Param 注解，例如：<br>
```java
@Mapper
public interface UserMapper {
 List<User> getAllUsers(@Param("order_by")String order_by);
}
```
```sql
<select id="getAllUsers" resultType="com.flameking.community.User">
    select * from user
 <if test="order_by!=null and order_by!=''">
        order by ${order_by} desc
 </if>
</select>
```



# ajax请求
```js
var json
const target = $.getJSON("/power/electron/" + getDateByOffset(offset), (res)=>{
    console.log(res)    //这里是可以得到JSon数据的
    json = res
})
console.log(json)   //但是就算再回调函数中赋值了json，函数外输出时值依然是undefined，因为函数里面的数据是异步加载的
json = target.responseJSon
```
因为ajax异步加载的原因，responsJSon我们再函数之外是获取不到的<br>
关闭异步的方法：<br>

```js
$.ajaxSettings.async = false;
````
但是执行过后记得重新开启起步`$.ajaxSettings.async = true;`，避免影响到其他的ajax异步请求

