Day_1

1. 环境搭建

技术选型

后端项目结构

sky-take-out

maven父工程,统一管理依赖版本,聚合其他子模块

sky-common

子模块,存放公共类,例如:工具类、常量类、异常类等

sky-pojo

子模块,存放实体类、VODTO

sky-server

子模块,配置文件、ControllerServiceMapper

sky-common

存放的是一些公共类,可以供其他模块使用

sky-pojo

存放的是一些 entityDTOVO

sky-server

存放的是 配置文件、配置类、拦截器、controllerservicemapper、启动类等

数据库

参考数据库设计文档

前后端联调

前端发送的请求,是如何请求到后端服务的?

前端请求地址:http://localhost/api/employee/login

后端接口地址:http://localhost:8080/admin/employee/login

nginx 反向代理

就是将前端发送的动态请求由 nginx 转发到后端服务器

nginx 反向代理的好处:

  1. 提高访问速度,nginx可以进行缓存
  2. 进行负载均衡,针对分布式系统
  3. 保证后端服务安全,不会对外公开自己的服务调用接口

配置方式

在文件 nginx.conf

反向代理的配置方式:

server{listen 80;server_name localhost;location /api/ {proxy_pass   http://localhost:8080/admin/;  #反向代理}}

nginx 负载均衡的配置方式:

upstream webservers{server 192.168.100.128:8080;server 192.168.100.129:8080;
}server{listen 80;server_name localhost;location /api/ {proxy_pass   http://webservers/admin/;  #负载均衡 默认为轮询}}

 2. 登录功能

员工表中的密码是明文存储,安全性太低,采用 MD5 加密格式

拦截器配置

需求:在调用用户登录接口的时候不需要进行 jwtToken 认证,其他接口都需要进行认证

拦截器对动态方法进行拦截

登录Controller

对于新登录的用户,生成一个 jwt 令牌

@PostMapping("/login")
@ApiOperation(value = "员工登录")
public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {log.info("员工登录:{}", employeeLoginDTO);Employee employee = employeeService.login(employeeLoginDTO);//登录成功后,生成jwt令牌Map<String, Object> claims = new HashMap<>();claims.put(JwtClaimsConstant.EMP_ID, employee.getId());String token = JwtUtil.createJWT(jwtProperties.getAdminSecretKey(),jwtProperties.getAdminTtl(),claims);EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder().id(employee.getId()).userName(employee.getUsername()).name(employee.getName()).token(token).build();return Result.success(employeeLoginVO);
}

登录service

因为数据库里存的是进行 md5 加密后的信息,在进行密码对比的时候,需要将前端传入的明文密码转为 md5 后再进行对比

 3. Swagger

Knife4j 是为Java MVC框架集成Swagger生成Api文档的增强解决方案

<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.2</version>
</dependency>

使用方式

1. 导入 knife4j maven坐标

2. 在配置类中加入 knife4j 相关配置

WebMvcConfiguration.java

@Bean
public Docket docket() {log.info("准备生产接口文档");ApiInfo apiInfo = new ApiInfoBuilder().title("苍穹外卖项目接口文档").version("2.0").description("苍穹外卖项目接口文档").build();Docket docket = new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo).select().apis(RequestHandlerSelectors.basePackage("com.sky.controller")).paths(PathSelectors.any()).build();return docket;
}

3. 设置静态资源映射,否则接口文档页面无法访问

protected void addResourceHandlers(ResourceHandlerRegistry registry) {log.info("开始设置静态资源映射");registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}

4. 访问

接口文档访问路径为 http://ip:port/doc.html

常用注解

注解

说明

@Api

用在类上,例如Controller,表示对类的说明

@ApiModel

用在类上,例如entityDTOVO

@ApiModelProperty

用在属性上,描述属性信息

@ApiOperation

用在方法上,例如Controller的方法,说明方法的用途、作用


4. 员工管理 

开发都是采用三层结构(MVC模式),具体查看源码

代码开发:

1. 设计接受前端传入的 DTO 

2. 在 Controller 定义执行方法

3. 在 Service,ServiceImpl 中进行实现方法逻辑

4. 在 Mapper 层进行对数据库的调用查询

5. Controller 返回前端需要的数据类型

新增员工

正常采用三层结构实现

@PostMapping
@ApiOperation("员工新增")
public Result save(@RequestBody EmployeeDTO employeeDTO) {log.info("新增员工:{}", employeeDTO);// 新增员工业务方法employeeService.save(employeeDTO);return Result.success();
}

程序存在问题

1. 在出现同样的 username 的时候,系统会报错;

该异常应被全局异常处理器处理

@ExceptionHandler
public Result exceptionHandler(SQLIntegrityConstraintViolationException ex) {//错误内容: Duplicate entry 'zhangsan' for key 'idx_username'final String message = ex.getMessage();if(message.contains("Duplicate entry")) {String[] split = message.split(" ");String username = split[2];String msg = username + MessageConstant.ALREADY_EXISTS;return Result.error(msg);}else {return Result.error(MessageConstant.UNKNOWN_ERROR);}
}

2. 当前登录用户的 id 如何存储

使用 ThreadLocal,是一个线程的局部变量,为每个线程单独提供一份存储空间,具有线程隔离效果,只有在线程内才能获取到对应的值,线程外则不能访问

在 sky-common 中已经封装为 BaseContext 类

员工分页查询

分页查询使用使用 mybatis 的分页插件 PageHelper 来简化分页代码的开发。

底层基于 mybatis 的拦截器实现,在 sql 语句后面进行拼接 limit

代码完善

日期时间在前端的显示结果不是我们想要的

解决方法:

1. 在属性上加入注解,对日期进行格式化

可以实现日期的序列化,但是只能实现这一个属性的序列化。 不推荐

2.  WebMvcConfiguration 中扩展Spring MVC的消息转换器,统一对日期类型进行格式化

protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {//自己创建一个消息转换器MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();// 为消息转换器 设置一个对象转换器,可以将java对象序列化为json数据converter.setObjectMapper(new JacksonObjectMapper());//将自己的消息转换器加入到容器里, 默认是放在最后一个// 0 -> 就是把这个消息转换器放在前面converters.add(0, converter);
}

启用禁用员工账号

需要一个 update 数据库的方法

在 EmployeeMapper.xml 编写 SQL

<update id="update" parameterType="Employee">update employee<set><if test="name != null and name != ''" >name = #{name},</if><if test="username != null and username != ''" >username = #{username},</if><if test="sex != null and sex != ''" >sex = #{sex},</if><if test="password != null and password != ''" >password = #{password},</if><if test="phone != null and phone != ''" >phone = #{phone},</if><if test="idNumber != null and idNumber != ''" >id_number = #{idNumber},</if><if test="status != null">status = #{status},</if><if test="updateTime != null">update_time = #{updateTime},</if><if test="updateUser != null">update_user = #{updateUser},</if></set>where id = #{id}
</update>

编辑员工信息

需要一个查询员工信息的接口,和上一个的修改员工信息的接口


5. 分类模块功能

思路与员工管理的一致,做着基本的crud

注:

在删除分类的时候,要求其下面没有挂载任何内容才可以


6. 公共字段自动填充

针对业务表里的公共字段进行维护

序号

字段名

含义

数据类型

1

create_time

创建时间

datetime

2

create_user

创建人id

bigint

3

update_time

修改时间

datetime

4

update_user

修改人id

bigint

实现思路

技术:注解、AOP、反射

思路:

1.自定义注解 AutoFill,用于标识需要进行公共字段自动填充的方法

2.自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值

3.在 Mapper 的方法上加入 AutoFill 注解

开发

自定义注解 AutoFill

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {//数据库操作类型: update insertOperationType value();}

自定义切面类 AutoFillAspect

@Aspect
@Component
@Slf4j
public class AutoFillAspect {/*** 指定切入点*/@Pointcut("execution(* com.sky.mapper.*.*(..)) &&             @annotation(com.sky.annotation.AutoFill)")public void autoFillPointCut(){}/*** 前置通知,在通知中进行公共字段的赋值*/@Before("autoFillPointCut()")public void autoFill(JoinPoint joinPoint) {log.info("开始进行公共字段的填充");// 在这里实现逻辑}}

实现逻辑:

1.  获取到当前被拦截到的方法的数据库操作类型

//获取到方法签名对象
MethodSignature signature = (MethodSignature)joinPoint.getSignature(); 
//获取方法上的注解对象
AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); 
// 获取到数据库的操作类型
OperationType operationType = autoFill.value();  

2. 获取到被拦截的方法的参数(实体对象)  这里约定: 参数里面的实体对象为第一个参数

Object[] args = joinPoint.getArgs();
if(args == null || args.length == 0) {return;
}
Object entity = args[0];

3. 获取赋值的数据

LocalDateTime now = LocalDateTime.now();
Long currentId = BaseContext.getCurrentId();

4. 通过反射来赋值

if(operationType == OperationType.INSERT) {//给4个公共字段赋值try {// 获取创建时间方法Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME,LocalDateTime.class);// 获取创建人方法Method setCreateUser =     entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);// 获取修改时间方法Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);// 获取修改人方法Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);// 赋值操作// 创建时间赋值setCreateTime.invoke(entity, now);// 创建人赋值setCreateUser.invoke(entity, currentId);// 修改时间赋值setUpdateTime.invoke(entity, now);// 修改人赋值setUpdateUser.invoke(entity, currentId);} catch (Exception e) {e.printStackTrace();}
}else if(operationType == OperationType.UPDATE) {//给2个公共字段赋值try {// 获取修改时间方法Method setUpdateTime =     entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);// 获取修改人方法Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);// 赋值操作// 修改时间赋值setUpdateTime.invoke(entity, now);// 修改人赋值setUpdateUser.invoke(entity, currentId);} catch (Exception e) {throw new RuntimeException(e);}
}else {// 既不是新增又不是修改throw new RuntimeException(MessageConstant.UNKNOWN_ERROR);
}

5. Mapper接口的方法上加入 AutoFill 注解

@AutoFill(OperationType.INSERT@AutoFill(OperationType.UPDATE)

6. 去掉业务层这个重复的代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/671252.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

行业唯一!易保全牵头编制的《区块链数据访问安全技术通则》发布

近日&#xff0c;易保全牵头参与编制的《区块链数据访问安全技术通则》经中国国际经济技术合作促进会正式发布&#xff0c;为中国区块链数据安全技术提供了标准参考。 易保全作为牵头起草单位、易保全CEO兼董事长刘刚担任主要起草人参与其中&#xff0c;在区块链技术安全风险…

美业SaaS系统多门店收银系统源码-【分润常见问题】讲解(一)

美业管理系统源码 博弈美业SaaS系统 连锁多门店美业收银系统源码 多门店管理 / 会员管理 / 预约管理 / 排班管理 / 商品管理 / 促销活动 PC管理后台、手机APP、iPad APP、微信小程序 ▶ 分润常见问题&#xff1a; 1、分润金额基数 所有分润计算的基数均为平台订单中各个商…

一个JDBC小工具

pom.xml 结构 <properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><mysql5>5.1.44<…

从ChatGPT革命性的对话系统,看人机交互模式6个阶段的演变

ChatGPT引领革命&#xff0c;看人机交互六步飞跃 ©作者|wy 来源|神州问学 引言 在科技的浪潮中&#xff0c;人机交互模式不断演进&#xff0c;从最初的简单指令输入到如今的智能对话系统&#xff0c;每一次革新都昭示着人类与机器交流方式的深刻变革。ChatGPT&#xff0…

RabbitMQ 是如何做延迟消息的 ?——Java全栈知识(15)

RabbitMQ 是如何做延迟消息的 &#xff1f; 1、什么是死信&#xff1f; 当一个队列中的消息满足下列情况之一时&#xff0c;可以成为死信&#xff08;dead letter&#xff09;&#xff1a; 消费者使用 basic.reject 或 basic.nack 声明消费失败&#xff0c;并且消息的 reque…

【C++】 认识多态 + 多态的构成条件详细讲解

前言 C 目录 1. 多态的概念2 多态的定义及实现2 .1 虚函数&#xff1a;2 .2 虚函数的重写&#xff1a;2 .2.1 虚函数重写的两个例外&#xff1a; 2 .3 多态的两个条件&#xff08;重点&#xff09;2 .4 析构函数为啥写成虚函数 3 新增的两个关键字3.1 final的使用&#xff1a;3…

Java面试题:多线程2

如何停止正在运行的线程 1,使用退出标志,使线程正常退出(run方法中循环对退出标志进行判断) 2,使用stop()方法强行终止(不推荐) 3,调用interrupt()方法中断线程 打断阻塞线程(sleep,wait,join),线程会抛出InterruptedException异常 打断正常的线程,可以根据打断状态来标记…

LLVM的ThinLTO编译优化技术在Postgresql中的应用

部分内容引用&#xff1a;https://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html LTO是什么&#xff1f; 链接时优化&#xff08;Link-time optimization&#xff0c;简称LTO&#xff09;是编译器在链接时对程序进行的一种优化。它适用于以文件为单位编译…

Llama3-Tutorial之XTuner微调Llama3个人小助手

Llama3-Tutorial之XTuner微调Llama3个人小助手 使用XTuner微调llama3模型。 参考&#xff1a; https://github.com/SmartFlowAI/Llama3-Tutorial 1. web demo部署 参考上一节内容已经完成web demo部署&#xff0c;进行对话测试, 当前回答基于llama3官方发布的模型进行推理生成&…

项目|保障房房产管理系统,政务房产解决方案

一、系统概况 保障房管理系统是是为了落实中央关于住房保障的相关政策&#xff0c;实现对低收入家庭住房状况的调查管理、保障计划及落实管理、保障申请及审核管理、保障户和保障房源档案管理等。 针对政府保障房产管理的一站式解决方案&#xff0c;专注于为解决复杂、繁琐的…

为何美国多IP服务器搭建蜘蛛池SEO更经济?

为何美国多IP服务器搭建蜘蛛池SEO更经济? 随着网络时代的不断演进&#xff0c;搜索引擎优化(SEO)已经成为企业和个人提升网站曝光度的必经之路。在这个过程中&#xff0c;蜘蛛池(Spider Pool)服务被广泛应用。但是有趣的是&#xff0c;美国多IP服务器搭建蜘蛛池SEO服务却相对…

【学习AI-相关路程-工具使用-自我学习-cudavisco-开发工具尝试-基础样例 (2)】

【学习AI-相关路程-工具使用-自我学习-cuda&visco-开发工具尝试-基础样例 &#xff08;2&#xff09;】 1、前言2、环境说明3、总结说明4、工具安装0、验证cuda1、软件下载2、插件安装 5、软件设置与编程练习1、创建目录2、编译软件进入目录&创建两个文件3、编写配置文…