当前位置: 首页 > news >正文

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. 去掉业务层这个重复的代码

相关文章:

Day_1

1. 环境搭建 技术选型 后端项目结构 sky-take-out maven父工程&#xff0c;统一管理依赖版本&#xff0c;聚合其他子模块 sky-common 子模块&#xff0c;存放公共类&#xff0c;例如&#xff1a;工具类、常量类、异常类等 sky-pojo 子模块&#xff0c;存放实体类、VO、DTO…...

2024.05.06作业

自由发挥应用场景&#xff0c;实现登录界面。 要求&#xff1a;尽量每行代码都有注释。 #include "yuanshen.h"yuanshen::yuanshen(QWidget *parent): QWidget(parent) {//窗口相关设置this->resize(1600,910);this->setFixedSize(1600,910);//窗口标题this-…...

什么是抖音橱窗?它和抖音小店有什么区别?普通人更适合做哪个?

大家好&#xff0c;我是电商糖果 相信有很多想在抖音卖货的朋友&#xff0c;都会搞不清抖音橱窗是什么&#xff1f; 甚至会把它和抖音小店当成一个项目&#xff0c;也不知道哪个更适合自己。 自己越了解发现越迷糊&#xff0c;有的说不需要直播&#xff0c;粉丝&#xff0c;…...

spring高级篇(九)

boot的执行流程分为构造SpringApplication对象、调用run方法两部分 1、Spring Boot 执行流程-构造 通常我们会在SpringBoot的主启动类中写以下的代码&#xff1a; 参数一是当前类的字节码&#xff0c;参数二是main的args参数。 public class StartApplication {public static…...

用wordpress建跨境电商独立站的5大优势

免费和开源 WordPress是一个免费的开源内容管理系统&#xff0c;用户可以自由下载、安装和使用&#xff0c;无需支付版权费用或订阅费用。开源特性也意味着用户可以根据自己的需求修改和定制代码&#xff0c;或者使用其他开发者提供的插件和主题来扩展和美化网站。 易用和灵活…...

Windows中安装的PostgreSQL 数据库如何重启

1. 使用Windows服务管理器 打开“运行”对话框&#xff08;按WinR键&#xff09;。输入services.msc并按回车&#xff0c;这将打开服务列表。在服务列表中找到PostgreSQL服务。它通常命名为“PostgreSQL”后面跟着版本号和实例名称&#xff0c;例如“PostgreSQL 13 - mydb”。…...

Remix框架实现 SSR

SSR SSR是一种网页渲染方式&#xff0c;它与传统的客户端渲染&#xff08;CSR&#xff09;相对&#xff0c;在日常的项目中我们更多是使用 CSR 的方式进行前端分离开发&#xff0c;渲染会在浏览器端进行。然而在SSR中&#xff0c;当用户请求一个网页时&#xff0c;服务器将生成…...

如何快速开发项目,提高开发效率

文章目录 一、问题描述二、问题解决1.需求分析2.架构设计3.技术选型4.正式开发 一、问题描述 有很多小伙伴在开发一个项目的时候&#xff0c;总是需要很长时间&#xff0c;效率很低&#xff0c;其实本质是没有掌握开发项目的关键和技巧 我下面列举一些问题&#xff0c;不知道…...

面试笔记——多线程使用场景

线程池使用场景&#xff08;CountDownLatch&#xff0c; Future&#xff09; CountDownLatch CountDownLatch&#xff08;闭锁/倒计时锁&#xff09;用来进行线程同步协作&#xff0c;等待所有线程完成倒计时&#xff08;一个或者多个线程&#xff0c;等待其他多个线程完成某件…...

02.0 基于Verilog控制LED灯每秒钟闪烁一次

本段代码是为Verilog初学者提供的一个名为led_blink简单实例Verilog模块&#xff0c;其功能是控制6个LED灯同步闪烁&#xff0c;每秒钟闪烁一次。 本例代码用于理解时序逻辑的概念&#xff0c;理解多个always模块完全并行执行的概念&#xff0c;讲授时可以与C语言的执行过程进行…...

C语言创建文件夹和多级目录

C调用系统命令创建多级目录 #include <stdio.h> #include <stdlib.h>int main() {const char *path "a/b/c";// 创建目录命令的字符串char mkdir_command[100];sprintf(mkdir_command, "mkdir %s", path);// 调用系统命令system(mkdir_comma…...

2024.5.6

#include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//设置窗口大小this->resize(1000,740);//设置窗口图标this->setWindowIcon(QIcon("C:\\Users\\Administrator\\Desktop\\pictrue\\Plants.png"));//设置窗口标题this-…...

mybatis配置获取自增主键

mybatis配置获取自增主键 【/n】 01 使用场景 当需要刚刚插入数据库的数据对应的新增主键时&#xff0c;通过配置xml文件&#xff0c;使数据库返回新增主键id&#xff0c;并把主键id与类参数对应 02 涉及配置 注解TableId(type IdType.AUTO)&#xff1a;在类主键id通过配…...

完整、免费的把pdf转word文档

在线工具网 https://www.orcc.online 支持pdf转word&#xff0c;免费、完整、快捷 登录网站 https://orcc.online 选择需要转换的pdf文件&#xff1a; 等待转换完成 点击蓝色文件即可下载 无限制&#xff0c;完整转换。...

使用 Lua 协程模拟 Golang 的 go defer 编程模式

封装 go 函数 在 使用 Lua 协程处理异步回调函数 中已经介绍 这里简要列下&#xff1a; 封装 go 函数---go 函数创建并启动一个协程 ---param _co_task function 函数原型 fun(_co:thread) function go(_co_task)local co coroutine.create(_co_task) -- 创建的协程是暂停的…...

网络通信协议,UDP和TCP,初步了解

UDP&#xff08;User Datagram Protocol&#xff09;和TCP&#xff08;Transmission Control Protocol&#xff09;是两种常见的网络通信协议&#xff0c;用于在计算机网络中进行数据传输。 1. TCP&#xff1a;Transmission Control Protocol&#xff08;传输控制协议&#xf…...

Golang | Leetcode Golang题解之第61题旋转链表

题目&#xff1a; 题解&#xff1a; func rotateRight(head *ListNode, k int) *ListNode {if k 0 || head nil || head.Next nil {return head}n : 1iter : headfor iter.Next ! nil {iter iter.Nextn}add : n - k%nif add n {return head}iter.Next headfor add > …...

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

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

Chatbot 在教育中的应用

Chatbot 在教育中的应用 基本信息 ​ 这篇博客主要介绍几篇Chatbot在教育领域中应用的文章&#xff0c;根据文章的侧重点不同&#xff0c;分为介绍教育理论&#xff0c;与介绍系统设计两类。从问题定义、技术方法、教育学理论、实验设计、结论证据几个方面概括各篇文章。 博…...

Apache和Nginx的区别以及如何选择

近来遇到一些客户需要lnmp环境的虚拟主机&#xff0c;但是Hostease这边的虚拟主机都是基于Apache的&#xff0c;尽管二者是不同的服务器软件&#xff0c;但是大多数情况下&#xff0c;通过适当的配置和调整两者程序也是可以兼容的。 目前市面上有许多Web服务器软件&#xff0c;…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案

在移动互联网营销竞争白热化的当下&#xff0c;推客小程序系统凭借其裂变传播、精准营销等特性&#xff0c;成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径&#xff0c;助力开发者打造具有市场竞争力的营销工具。​ 一、系统核心功能架构&…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋

随着工业以太网的发展&#xff0c;其高效、便捷、协议开放、易于冗余等诸多优点&#xff0c;被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口&#xff0c;具有实时性、开放性&#xff0c;使用TCP/IP和IT标准&#xff0c;符合基于工业以太网的…...

shell脚本质数判断

shell脚本质数判断 shell输入一个正整数,判断是否为质数(素数&#xff09;shell求1-100内的质数shell求给定数组输出其中的质数 shell输入一个正整数,判断是否为质数(素数&#xff09; 思路&#xff1a; 1:1 2:1 2 3:1 2 3 4:1 2 3 4 5:1 2 3 4 5-------> 3:2 4:2 3 5:2 3…...