aurora博客复现总结

博客地址

博客源码链接: https://github.com/linhaojun857/aurora

前端

后台前端的部分目前知识粗略看了,首先在启动页面app.vue中,会先进入generaMenu菜单生成这个函数中,其中会访问后端的/api/admin/user/menus接口,这时如果后端没有用户信息security会拒绝访问返回错误的flag,前端判断flag,如果是错误的值那么就跳转到login页面中(login.vue是唯一一个显式加入router路由的),如果后端存有用户信息,那么就会将前端组件的路由、组件位置和组件图标返回给前端,前端根据这个动态的生成路由。这样做能够控制用户能够看到的页面,方便权限控制。

在app.vue中,每生成一次页面都会调用一次report函数,这个函数会访问后端的report接口,上报访客信息。

剩下的就是页面切换、页面设计和常规的访问接口设计了。

在部署到服务器时,使用npm run buid命令,构建项目,在docker中下载nginx作为前端的服务器,更改nginx的默认访问页面为打包后得到的index.html页面位置,然后设置请求转发给运行了后端项目的容器。这里注意的是不同容器之间的通信是要设置网络模式的,我使用的是link模式,link模式的大致方法是在配置文件中将ip地址设置为目标容器的名称,运行容器的时候使用link指定该目标容器即可。

后端

后端的部分,真的是感慨作者的开发功底,使用了springboot, mybatis plus作为主要的框架,然后其中还使用了spring security权限校验,消息队列,定时任务,多方式登录,拦截器等功能。在项目中代码严谨,耦合度低,设计规范。其中还有很多地方,我看到就会觉得 哇 还能这样搞的!一时半会想不起来,边写边想把。

mybatis plus

在项目中首先完成基本的框架,其它的额外功能先不搞,先引入mybatis plus的依赖,这个时候一个很坑的地方就来了,依赖中的mybatis plus的版本要和spingboot的版本相对应,否则启动时就会出现无法创建sqlsession的错误,没法正常启动。引入依赖之后在项目的yml中配置相关数据,mybatis plus的本质上还是使用jdbc连接的(对jdbc的另一层封装?目前的理解,上次搜狐的面试官也问过我这个问题,后面看一下)。先在spring datasource中配置数据库的信息包括jdbc、数据库地址、数据库连接池等(这个使用的应该就是SPI服务者使用的接口功能吧,框架规定了如何调用这个接口,接口的具体功能,然后实现交给各种厂商实现,实现后得到的jar作为依赖引入,springboot再在配置中指定这个依赖)。在配置mybatis-plus中要配置mapper.xml的地址和日志格式。在启动类上配置mapperscan注解,这样会把每个mapper交给springboot管理,或者在每个mapper上加上mapper注解也可以,但是不使用@Repository注解,idea会报警告,提示找不到这个bean,直接忽略即可。该注解的作用不只是将类识别为Bean,同时它还能将所标注的类中抛出的数据访问异常封装为 Spring 的数据访问异常类型。

mybatis plus有代码生成器的功能,在pom中导入代码生成器的依赖,然后根据模板按照自己的需求编写代码生成器实现类。(这里要注意的是mybatis plus的代码生成器依赖中包括mybatis plus extension的依赖,而mybatis plus starter中也包括这个依赖,两者可能会发生冲突导致starter的依赖无法使用,这样就无法配置Mybatis plus的一些扩展功能 如 分页功能)。

编写redisconfig配置类设置分页插件的功能。

@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
swagger

在项目的构件中对于接口的测试十分重要的。使用集成了swagger的knif4j,引入依赖,然后编写配置类,启动swagger配置

@Configuration
@EnableSwagger2WebMvc
public class Knif4jConfig {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
//                .protocols(Collections.singleton("https"))
//                .host("https://www.linhaojun.top")
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.wzh.myaurora.controller"))
                .paths(PathSelectors.any())
                .build();
    }
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("aurora文档")
                .description("aurora")
                .contact(new Contact("wzh", "", ""))
                .version("1.0")
                .build();
    }
}

然后在需要扫描的接口上加入api注解即可。

redis

使用redis缓存能够减少对数据库的访问压力,加快访问的相应速度。老规矩Pom中引入依赖,在yml中配置redis的连接地址、密码和连接池等信息。在服务器上要下载redis启动。如果自己需要对redis中的一些配置做更改可以编写配置类返回满足自己要求的redistemplate对象。一般来说redis默认的对象存储序列化格式会导致无法查看的问题,编写配置类指定更容易查看的序列化方式。

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        jackson2JsonRedisSerializer.setObjectMapper(mapper);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

另外一般会编写redisservice类包装redistemplate中对redis数据库的操作功能,使得使用方法更加的便捷。

webmvc拦截器

在项目复现的过程中,设置了一个拦截器用来拦截请求中是否包含currentPage,pageSize这两个参数,如果包含这两个参数就用其初始化一个page对象,然后调用pageUtil类将page保存到threadlocal本地变量中,后续对请求的处理中如果需要有需要这个page对象,就使用pageutil从threadlocal变量中取出。当这个请求处理结束之后将threadlocal清空。另外需要编写配置类将该拦截器加入到spring中。

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private PaginationInterceptor paginationInterceptor;
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowCredentials(true)
                .allowedHeaders("*")
                .allowedOrigins("*")
                .allowedMethods("*");
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 这里将定义的paginationInterceptor加入到拦截器中
        // 拦截器是定义在spring ioc容器中的,能够使用其中的组件,位于filter过滤器后面
        // 这个拦截器的作用是将请求中包含的当前页码,每页的页数得到赋值给pageutil中的page,以供后续的使用
        registry.addInterceptor(paginationInterceptor);
    }

}

关于为什么要使用这个拦截器,本质上是为什么要使用本地变量保存这样一个固定的page对象呢?我现在个人理解是如果不使用threadlocal保存page对象的话,在这次请求中所涉及到的地方都需要new一个page对象来进行操作,这样会造成资源浪费,而且每一个请求都是一个线程,多个请求并发过来page是一个共享变量会导致处理结果错误。

知识点

复现的过程中自己从头建立了一个新的项目去除spring security、消息队列、定时任务功能,只实现基本的请求处理功能。目前是是把article相关的内容做好了。其中感叹于自己对于Java认识的浅薄和对springboot工程的完整度的强大的感叹。

重要的一点,构建自己的返回对象 resultVO,这样能够让前后端都遵守一个规范,方便开发。

针对前端传来的参数设计相应的vo value object来接受处理,针对前端需要的数据设计相应的dto data trans object对象来包含数据

项目中经常使用到的常数,将其总结为constant接口来保存,这个接口只是保存常数

如果有需要可以定义自己的异常类来处理特殊的情况

在处理请求时,如果涉及到多个查询之类的可以使用CompletableFuture.supplyAsync方法传入一个实现类thread接口的匿名类来得到一个future对象进行异步调用,加快处理速度。

队列转为stream流使用map对其中元素进行处理,然后重新转为队列

在article中有一个文章上传功能,这个功能实现设计的我觉得很巧妙。通过定义的articleImportStrategyContext类,里面有一个map数据类型,key是上传策略,value是对应的实现类(使用@autowired注解map,会自动将value的实现类注入到其中,其实现类的@Service(“normalArticleImportStrategyImpl”)的名称就是key)。前端传来文件流和上传策略,通过上传策略articleImportStrategyContext找到该策略的实现类实现上传。

@Controller注解也是Spring MVC中的注解,它将类标记为一个控制器,用于处理HTTP请求,但是返回的结果是一个视图(View),通常用于构建传统的Web应用。@RestController注解是Spring MVC中的注解,它将类标记为一个控制器,用于处理HTTP请求,并将返回的结果直接写入到HTTP响应体中,通常用于构建RESTful API。如果在controller类中使用的是@Controller,但是没有返回一个视图而只是一个字符串之类的,就会导致如下错误。在springmvc中我们是使用viewResolver,通过在controller中return的前缀来决定跳转到相应的视图,如果返回的字符串没有对应的视图,viewResolver就找不到也就会报错。

Circular view path [login]: would dispatch back to the current handler URL [/ssmtest1/login] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)

如果想要用视图去展示,应该要设置好视图展示页面,比如说用一个模板语言来接收返回的数据(thymeleaf或者freemarker等),也可以用jsp接收,但是SpringBoot官方是不推荐用jsp的,而是建议使用thymeleaf作为模板语言,这里我以thymeleaf为例。引入thymeleaf的依赖,然后在application.properties中配置thymeleaf,配置完之后在/src/main/resources/template中创建你要返回的视图模板,如果你的controller中返回的值为index,那模板创建的名称就为index.html,最后在ctroller中设置返回值为index,就能够返回这个视图了。

在传统的Web应用中访问ctroller层是会给你返回一个视图的(也就是页面),那时的Web应用也还不是前后端分离的,后端访问数据库,执行逻辑,得到结果后创建视图返回给浏览器显示。

mybatis中,可以使用collection和association来处理一对多和多对一的关系

其中每个标签中有2中种使用方式,一种是嵌套查询,一种是嵌套结果

嵌套查询会在主查询中,去调用子查询

嵌套结果只需要查询一次,将结果进行封装

https://blog.csdn.net/zifengye520/article/details/121922749

@Transactional(rollbackFor = Exception.class)

Springboot的事务管理,使用注解,然后就会为该方法创建一个代理帮助方法中的内容开启事务,方法执行完后关闭事务,事务的默认传播级别是REQUIRED,当使用了该注解的内部调用了另一个也开启了事物的方法之后,该方法就会检测当前线程之后是否存在事务(调用它的方法是否开启了事务),如果有那么就加入这个事务,否则创建一个新的事务。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值