1.1 数据库
数据库:
- 创建一个空白数据库reggie,然后导入执行SQL文件
- 创建的表如下:
1.2 项目依赖
项目依赖:
pom.xml文件内的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>reggie</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- springBoot starter-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>compile</scope>
</dependency>
<!-- MyBatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<!-- fastJson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<!-- Mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.23</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.5</version>
</plugin>
</plugins>
</build>
</project>
1.3 项目yaml配置文件
yaml配置文件:
server:
port: 8080
spring:
application:
#应用名称
name: reggie_take_out
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/reggie?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
mybatis-plus:
# 配置xml文件扫描包位置
mapper-locations: classpath:/mappers/*.xml
# 配置实体类扫描包位置,可以给该包内实体类自动起别名
type-aliases-package: com.reggie.entity
configuration:
#address_book->AddressBook
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: ASSIGN_ID
1.4 前端资源
前端资源:
直接将资料提供的backend
和front
文件夹直接复制到resource
目录下
1.5 静态资源访问配置
添加配置类添加静态资源访问目录:
- 定义一个配置类,继承WebMvcConfigurationSupport类
- 实现addResourceHandlers(ResourceHandlerRegistry registry)方法
- 在方法内部配置访问路径
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
addResourceHandler
:添加URL响应地址目录。addResourceLocations
:添加实际资源目录
@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("开始静态资源映射");
// 当"/backend/**"的请求进来,自动响应到静态资源目录"classpath:/backend/"
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
}
}
1.6 Knife4j接口文档
配置Knife4j:
引入依赖:
<!-- knife4j-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
创建配置类,修改静态资源访问规则:
配置类:Knife4jConfiguration
@Configuration
@EnableOpenApi
// @EnableKnife4j
// @EnableSwagger2
public class Knife4jConfiguration {
@Bean
public Docket docket() {
Docket docket = new Docket(DocumentationType.OAS_30)
.apiInfo(new ApiInfoBuilder()
.title("我的标题")
.description("我的描述")
// .termsOfServiceUrl("http://www.xx.com/")
.contact(new Contact("knife", "https://knife.blog.csdn.net/", "xx@qq.com"))
.version("1.0")
.build())
// 分组名称
.groupName("all")
.select()
// 这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.reggie.controller"))
.paths(PathSelectors.any())
.build();
return docket;
}
}
修改静态资源配置:WebMVCConfig
@Configuration
public class WebMVCConfig extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
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/");
}
}
在启动项目后可以访问localhost:8080/doc.html访问接口文档对接口进行测试
二、后台登录功能
2.1 需求
需求:
- 访问登录页面,输入账号密码
- 后端进行账号密码校验,注意密码需要MD5加密
- 返回给前端的数据需要包含
code
、data
、msg
流程图:
前端页面 /backend/page/login.html
在前端页面login需要注意的地方
-
1.前端根据后端返回的结果内的code 判断是否登录成功
-
2.data保存的是用户的登录信息
-
msg保存的是登录失败返回的失败信息
这些都是我们后端需要处理返回给前端的数据
优化思路:等项目大体完成后再次优化
(后面优化可以生成token保存到redis内加快性能,还可以使用SpringSecurity进行权限校验,等后面二次开发的时候优化)
2.2 实现
流程:
1.获取请求体内的数据employ
2.将提交的密码进行MD5加密
Spring内部已经封装好内置的方法类了,直接调用即可
String md5Str = DigestUtils.md5DigestAsHex(“原串”.getBytes());
3.根据用户名去数据库内查询用户是否存在并且状态为可登录(status=1)
4.校验密码是否正确
5.将用户信息保存到session内
6.获取用户数据封装到MyResult内返回
employController:
@RestController
@RequestMapping("/employee")
@Api(tags = "employee")
public class employController {
@Autowired
private employServiceImpl employService;
@ApiOperation("登录")
@PostMapping("/login")
public MyResult<Employee> login(HttpServletRequest request, @RequestBody Employee employee){
// 1.MD5加密
String MD5Password = DigestUtils.md5DigestAsHex(employee.getPassword().getBytes());
// 2.根据用户名查询数据库
LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Employee::getUsername,employee.getUsername());
Employee employee1 = employService.getOne(wrapper);
if (employee1==null){
return MyResult.error("查无此人!");
}
// 3.校验密码
if (!employee1.getPassword().equals(MD5Password)){
return MyResult.error("密码错误!");
}
// 校验用户状态是否正常
if (employee1.getStatus()==0){
return MyResult.error("用户账号被禁用!");
}
// 4.将用户id信息保存到session内
request.getSession().setAttribute("employee",employee1.getId());
// 5.封装信息并返回
return MyResult.success(employee1);
}
@PostMapping("/employee/logout")
@ApiOperation("退出登录")
public MyResult logout(HttpServletRequest request){
// 1.清除session内保存的用户id
request.getSession().removeAttribute("employee");
// 2.向前端返回数据
return MyResult.success("退出成功!");
}
}
employServiceImpl:
@Service
public class employServiceImpl extends ServiceImpl<employMapper, Employee> implements employService {
}
employMapper:
@Mapper
public interface employMapper extends BaseMapper<Employee> {
}
2.3 完善
需要完善的地方:
-
前面我们已经完成了后台系统的员工登录功能开发,但是还存在一个问题:用户如果不登录,直接访问系统首页面,照样可以正常访问。这种设计并不合理,我们希望看到的效果应该是,只有登录成功后才可以访问系统中的页面,如果没有登录则跳转到登录页面。
-
那么,具体应该怎么实现呢?
答案就是使用过滤器或者拦截器,在过滤器或者拦截器中判断用户是否已经完成登录,如果没有登录则跳转到登录页面
后期完善思路:使用SpringSecurity结合JWT生成唯一token保存到redis内进行身份验证,因为如果只是将用户登录身份信息保存到session的话,浏览器会进行缓存,有时候会使用户跳过身份验证直接访问内部页面
实现:
- 在这里我后端使用拦截器实现
- 如果不能放行的话,会实现页面重定向转发,使用了thymeleaf视图引擎
WebMVCConfig
// 配置拦截器
@Override
protected void addInterceptors(InterceptorRegistry registry) {
// 判断用户是否登录拦截器
List<String> excludePathPatterns = new ArrayList<>();
excludePathPatterns.add("/backend/**");
excludePathPatterns.add("/front/**");
excludePathPatterns.add("doc.html");
excludePathPatterns.add("/webjars/**");
excludePathPatterns.add("/employee/login");
excludePathPatterns.add("/employee/logout");
excludePathPatterns.add("/error");
excludePathPatterns.add("/index");
registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns(excludePathPatterns);
}
loginInterceptor:
@Slf4j
@Component
public class loginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("拦截请求:"+request.getRequestURI());
Object employee = request.getSession().getAttribute("employee");
if (employee==null) {
// 拦截请求 转发到登录页面
falseResult(response);
return false;
}
log.info("请求放行:"+request.getRequestURI());
return true;
}
public void falseResult(HttpServletResponse response) throws IOException {
response.sendRedirect("/index");
}
}
IndexController:
@Controller
public class indexController {
@RequestMapping("/index")
public String index(){
return "/login.html";
}
}