瑞吉总结

一.MyBatis-Plus

1.主键生成雪花算法:@TableId(idType.ASSIGN_ID)

@TableId注解用来指定该实体类属性为表主键,默认值为生成雪花算法,AUTO是自增,INSERRT是需要手动添加

2.实体类映射对应的数据库表: @TableName(“table_name”)

当实体类和数据库的表名不同却想映射两者时,使用该注解,参数写上数据库的表名即可完成映射

3.1.字段内容自动填充:@TableField(fill = FieldFill_INSERT)

实现这个功能需要创建一个组件实现MetaObjectHandler接口,实现insertFill() 和 updateFill()方法

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("公共字段自动填充[insert]...");
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("createUser",BaseContext.getCurrentId());
        metaObject.setValue("updateUser",BaseContext.getCurrentId());
    }

3.2.乐观锁:@Version

给表新增一个version字段,实体类属性上添加该注解,sql语句中就会添加where version = ?,这样在并发事务时,如果事务A在更新前事务A先执行了,version就会加1,事务A的sql无法匹配条件从而取消本次更新。

//旧版本用法
@Configuration
public class MybatisPlusConfig {
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor () {
        return new OptimisticLockerInterceptor();
    }
}

//3.4.0之后
@Configuration
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

//另外:分页器也在这里添加 interceptor.addInnerInterceptor(new PaginationInnerInterceptor());

二.解决Property ‘mapperLocations‘ was not specified or no matching resources found问题

在编写mybatis映射文件时,将XML文件放到了包下,而不是resources文件夹下,maven在打包的时候,默认是不会把xml文件打包编译,因此需要手动在pom文件配置,让maven在编译时把xml文件也进行输出

<!-- 项目打包时会将java目录中的*.xml文件也进行打包 -->
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>
    
# 因为xml文件在java目录中,所以要扫描所在目录
mybatis-plus.mapper-locations=classpath:com/atguigu/yygh/hosp/mapper/xml/*.xml

神TM枚举类,Spring封装pojo类型的返回值时是根据setter方法来确定属性的,由于Result里有个isOk方法,所以ok被当作了属性(布尔类型返回值的getter方法默认前缀就是is)

三.SpringBoot相关

1.@ControllerAdvice注解(用于全局异常处理)

@RestControllerAdvice   //一种对所有controller增强的组件,能够根据条件拦截下来
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)  //出现异常就拦截下来,走自定义的方法
    public Result error(Exception e){
        e.printStackTrace();
        return Result.fail();
    }
}

2.@Mapper和@MapperScan的区别

两者都是为指定mapper的接口生成对应的实现类,@Mapper加在一个mapper接口上,但使用@MapperScan可以扫描指定的包路径,为扫描路径的所有mapper接口生成对应的实现类,该注解一般加在配置类上。

3.关于Springboot的测试类操作

正常操作是导入junit依赖,但在springboot中只需要引入springboot-starter-test依赖(内嵌了junit)

就算是测试类也要写主包的启动类

在测试类中添加@SpringBootTest(参数classes指定为主包的启动类)和@RunWith(SpringRunner.class)注解【RunWith是junit和spring整合用的,让测试运行于Spring测试环境】

另外:如果测试中不需要连接数据库,添加@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class}),springboot是默认要连接数据库的,这个exclude参数就是说明不需要连接数据库。

四.EasyExcel

将数据集合导出到Excel:

    public void exportDictData(HttpServletResponse response) {
        try {
            response.setContentType("application/vnd.ms-excel");
                        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            response.setCharacterEncoding("utf-8");

            String fileName = URLEncoder.encode("数据字典", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

            List<Dict> list = this.baseMapper.selectList(null);
            //获取浏览器发送的响应输出流
            EasyExcel.write(response.getOutputStream(), DictEeVo.class)
                    .sheet("dict").doWrite(list);

        } catch (Exception e) {
            e.printStackTrace();
        }
        
        
 @Data
public class DictEeVo {
    @ExcelProperty(value = "id" ,index = 0)
    private Long id;

    @ExcelProperty(value = "上级id" ,index = 1)
    private Long parentId;

    @ExcelProperty(value = "名称" ,index = 2)
    private String name;

    @ExcelProperty(value = "值" ,index = 3)
    private String value;

    @ExcelProperty(value = "编码" ,index = 4)
    private String dictCode;
}
    //从Excel读取数据字典导入
//Service层
    public void importDictData(MultipartFile multipartFile){
        try {
            EasyExcel.read(multipartFile.getInputStream(),DictEeVo.class,
                    new DictDataListener(baseMapper)).sheet().doRead();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    
    
 public class DictDataListener extends AnalysisEventListener<DictEeVo> {
    private DictMapper dictMapper;
    public DictDataListener(DictMapper dictMapper){
        this.dictMapper = dictMapper;
    }

    //excel一行一行的读取
    @Override
    public void invoke(DictEeVo dictEeVo, AnalysisContext analysisContext) {
        Dict dict = new Dict();
        BeanUtils.copyProperties(dictEeVo,dict);
        dictMapper.insert(dict);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

五.Spring Cache + Redis

@EnableCaching开启Cache

# Redis配置
#spring.redis.host=192.168.44.165
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
// 对结果进行缓存,获取结果时如果缓存中没有就将存入缓存,有则从缓存中拿。用于查询方法
// keyGenerator:属性用于自定义键的命名方式
// value:缓存名,必填,它指定了你的缓存存放在哪块命名空间
@Cacheable(value = "dict",keyGenerator = "keyGenerator")
    
@Bean  //redis配置类中
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }

@CachePut:每次都会执行,并将结果存入指定的缓存中,用于新增方法
@CacheEvict: 清空指定的缓存。一般用在更新或者删除方法上
    属性:allEntries->方法调用后将立即清空所有的缓存
        beforeInvocation->方法执行前就会清空缓存

六.Nacos + Feign

feign能够依照Restful风格帮助快速开发服务间的调用

使用Feign的前提是服务已经在Nacos中注册

// 导依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <scope>provided</scope>
</dependency>

// 创建一个接口
//指定要调用的服务名,该服务名需要在对应的服务模块的配置文件中配置
//(spring.application.name=service_cmn)
@FeignClient("service-cmn") 
public interface DictFeignClient {
    // 医院等级的value可能不唯一,所以还需要dictCode
    @GetMapping("/admin/cmn/dict/getName/{dictCode}/{value}")
    // 有一点要注意!!!@PathVariable中要指定名称
    // 在普通类上定义@PatnVariable注解时value值可以不用声明,直接写值就好,但是在Feign接口下使用该注解,则需要显示声明value,否则会报错
    String getName(@PathVariable("dictCode") String dictCode, @PathVariable("value") String value);

    @GetMapping("/admin/cmn/dict/getName/{value}")
    String getName(@PathVariable("value") String value);
}
        
        

七.关于前后端Restful风格的参数传递与接收

1. @RequestParam : 该注解常用于Put修改方式

​ 后端的RequstMapper路径无需写参数,参数会在请求头中出现,跟在请求路径后面,

http://xxxxxxx?param1=xxx&param2=xxx 的显示出现,多个参数时RequestParam需要指明参数名

​ 前端对应的数据请求形式为: params:{ ‘param1’ : xxx, ‘param2’ : xxxx }

2. @RequestBody : 该注解常用于Post方式进行新增

​ 后端的RequstMapper路径无需写参数,RequestBody用于注解对象,接收前端传来的json格式对象

​ 前端对应的数据请求发送形式为 : data : object

3.@ResponseBody:该注解常置于Controller类上方

​ 将方法的返回值写入response的body区,转化为json格式

4. @PathVariable : 该注解常用于Get方式进行查询

​ 后端的RequstMapper路径以参数为{param}形式设置,前后端的请求发送格式为 http://xxxxxxx/{param1}/{param2}

​ 实际发送的请求格式为http://xxxxxxx/param1/param2,参数会跟在请求路径上

八.服务器docker容器连接相关

image-20221110195741623 image-20221110195751126

如果是连接本地虚拟机的只需要设置常规:端口写docker开放的端口,ip写虚拟机的ip

如果是连接云服务器的虚拟机,常规的ip写localhost(127.0.0.1),SSH写云服务器的账号(root)和密码(xxxxxxxxx)(也就是该虚拟机主机的登录用户名和登录密码,可以在阿里云控制台修改),端口默认22,主机ip写公网的ip,私网无法连接

mysql 127.0.0.1 Touko217 redis 127.0.0.1 123456

九.reggie相关知识点

1.ThreadLocal类:

Ⅰ.内置一个ThreadLocalMap属性,是一个Entry(k-v),用来存储当前线程的一个变量。对该变量进行线程间的隔离,每个线程都有一个该变量的副本,每个线程只能访问修改各自的变量副本。一般用private static修饰

Ⅱ.使用场景:

①每个线程需要有自己单独的实例
②实例需要在多个方法中共享,但不希望被多个线程间共享,例如存储用户登录的Session信息

2.异常处理器:

@ExcepionHandler:用于统一处理抛出的异常,置于自定义方法的上方,注解参数为xxxException.class,表示处理指定的异常,并接收异常在自定义方法中对异常进行处理,自定义方法的参数也为异常类型,用于接收异常。

@ControllerAdvice:对Controller的一种增强。用于拦截规则,然后具体你想做更细致的拦截筛选和拦截之后的处理,你自己通过@ExceptionHandler@InitBinder@ModelAttribute这三个注解以及被其注解的方法来自定义。

//参数annotation表示对添加指定注解的Controller进行拦截
@ControllerAdvice(annotations = {RestController.class, Controller.class})
public class GlobalExceptionHandler {
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){
        String exMessage = ex.getMessage();
        log.info(exMessage);
        if (exMessage.contains("Duplicate entry")){
            String[] split = exMessage.split(" ");
            String s = split[2] + "已存在";
            return R.error("s");
        }
        return R.error("未知错误");
    }
}

3.自定义异常的创建

​ RuntimeException<—-Exception<—-Throwable

​ 创建一个类继承RuntimeException类,重写父类的构造方法,即Throwable的构造方法public Throwable(String message),该方法用于在类内部设置message,detailMessage = message;

​ 定义出的自定义异常使用时可以用getMessage()获取detailMessage

4.泛型方法

<T> T 用法:

​ public static T methodName:第一个表示声明该方法是泛型,第二个T为类型定义为T

②T 用法:

​ 和①一样的意思,只是不加的话需要在类上加 “ClassName,

​ 另外,静态方法无法访问类上定义的泛型;如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。即: public static void MethodName(T t)

​ 总结:静态方法由于随着类的加载而加载,不能访问类的泛型(因为在创建对象的时候才确定),因此必须定义自己的泛型类型。

十.JackJson

<!-- 导入jackjson依赖包 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.76</version>
</dependency>

创建一个继承ObjectMapper的类

1.ObjectMapper的常用方法

​ ObjectMapper.writeValueAsString(Object obj) :能够将java对象转为json字符串

​ ObjectMapper.readValue(String,Class<>) :能够将json字符串转化为指定类的对象

2.自定义类型转换器

先定义一个自定义类型的转换器,然后再扩展mvc的消息转换器

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);
    }
}
    /**
     * 扩展mvc的消息转换器,自定义类继承WebMvcConfigurationSupport(spring-boot-starter-web包)
     * @param converters
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("扩展消息转换器");
        //创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        //将消息转换器添加到mvc框架的转换器集合中
        converters.add(0,messageConverter);
    }

//	静态资源映射
@Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        log.info("开始进行静态资源映射...");
        //如果访问路径是addResourceHandler中的filepath 这个路径 那么就 映射到访问本地的addResourceLocations 的参数的这个路径上,这样就可以让别人访问服务器的本地文件了,映射的真实路径末尾必须加 / ,不然映射不到
        //classpath指的是类路径,也就是编译之后的target文件夹下的WEB-INF/class文件夹
        registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
        registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");

    }

十一.Filter拦截器(Web三大组件之一Servlet、Listener)

@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")//表示拦截所有路径
@Order(Integer value) //value越小,优先级越高

1.自定义类继承Filter接口,Filter中包含三个方法:

​ ①init(FilterConfig filterConfig):

​ ②doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3):

​ 进行路径的拦截、处理和放行,调用filterChain.doFilter(request,response);放行

​ 调用response.getWriter().write(XXX);向前端返回数据

​ ③destroy()


  转载请注明: 流浪秃球计划 瑞吉总结

 上一篇
反射 反射
第一个阶段(源代码阶段): 先从java文件按成员变量,构造方法,成员方法通过javac编译成class文件。如上图Person.java-->Person.class 第二个阶段(Class类对象阶段): 通过类加载器把clas
2022-11-18
本篇 
瑞吉总结 瑞吉总结
一.MyBatis-Plus1.主键生成雪花算法:@TableId(idType.ASSIGN_ID)@TableId注解用来指定该实体类属性为表主键,默认值为生成雪花算法,AUTO是自增,INSERRT是需要手动添加 2.实体类映射对应的
2022-11-17
  目录