EMOS个人教程-第2章 从零构建后端项目基础篇
1 本章介绍
2 创建 SpringBoot 项目



将application.properties改为application.yml
配置tomcat
server:
tomcat:
uri-encoding: UTF-8
threads:
max: 200
min-spare: 30
connection-timeout: 5000ms
port: 8080
servlet:
context-path: /emos-wx-api
配置数据连接池
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/emos?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
initial-size: 8
max-active: 16
min-idle: 8
max-wait: 60000
test-while-idle: true
test-on-borrow: false
test-on-return: false
在pom.xml中添加配置
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
配置redis数据源
redis:
database: 0
host: localhost
port: 6379
password: 123456
jedis:
pool:
max-active: 1000
max-wait: -1ms
max-idle: 16
min-idle: 8
配置mongo数据源
data:
mongodb:
host: localhost
port: 27017
database: emos
authentication-database: admin
username: admin
password: 123456
3 配置MyBatis
3.1 创建数据库连接




3.2 选中数据表,生成MyBatis文件



3.3 修改yml文件,添加MyBatis配置信息
mybatis:
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: com.example.emos.wx.db.pojo
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
3.4 设置日志输出
logging:
level:
root: info
com.example.emos.wx.db.dao: warn
pattern:
console: "%d{HH:mm:ss} %-5level %msg%n"
4 创建自定义异常类
- 为什么要继承RuntimeException?
- Exception类型的异常必须手动处理
- RuntimeException异常既可以自动处理,也可以手动处理
- 包含的属性
- 状态码
- 异常消息
package com.example.emos.wx.exception;
import lombok.Data;
@Data
public class EmosException extends RuntimeException {
private String msg;
private int code = 500;
public EmosException(String msg) {
super(msg);
this.msg = msg;
}
public EmosException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public EmosException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public EmosException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
}
5 封装Web返回对象
- JavaWeb项目需要统一数据返回格式
- 业务状态码
- 业务消息
- 业务数据
- 导入httpcomponents库
- 定义了很多HTTP状态码
- 免去我们自定义状态码常量
- R类继承自HashMap
- 封装方法
- ok方法
- error方法
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.14</version>
</dependency>
package com.example.emos.wx.common.util;
import org.apache.http.HttpStatus;
import java.util.HashMap;
import java.util.Map;
public class R extends HashMap<String,Object> {
public R(){
put("code", HttpStatus.SC_OK);
put("msg","success");
}
public R put(String key,Object value){
super.put(key,value);
return this;
}
public static R ok(){
return new R();
}
public static R ok(String msg){
R r=new R();
r.put("msg",msg);
return r;
}
public static R ok(Map<String,Object> map){
R r=new R();
r.putAll(map);
return r;
}
public static R error(int code,String msg){
R r=new R();
r.put("code",code);
r.put("msg",msg);
return r;
}
public static R error(String msg){
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR,msg);
}
public static R error(){
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR,"未知异常,请联系管理员");
}
}
6 利用Swagger搭建 REST API
6.1 本课程使用Swagger2
6.2 添加依赖库
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
6.3 配置Swagger
- (ApiInfoBuilder )定义Swagger页面基本信息
- (ApiSelectorBuilder )哪些类中的方法会出现在Swagger上面
- 开启对JWT的支持
- List
:用户需要输入什么参数 - AuthorizationScope[]:JWT认证在Swagger中的作用域
- List
:令牌的作用域 - List
:令牌上下文
- List
package com.example.emos.wx.config;
public class SwaggerConfig {}
7 创建Web方法测试Swagger
7.1 编写Web接口TestController
package com.example.emos.wx.controller;
import com.example.emos.wx.common.util.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
@Api("测试Web接口")
public class TestController {
@PostMapping("/sayHello")
@ApiOperation("最简单的测试方法")
public R sayHello(){
return R.ok().put("message", "HelloWorld");
}
}
7.2 类声明要加上@API注解
7.3 Web方法要加上@ApiOperation注解
测试连接:
http://127.0.0.1:8080/emos-wx-api/swagger-ui.html
8 配置后端验证功能
8.1 使用Validation库
8.2 添加依赖库
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
8.3 创建Form类
- 类声明要添加@ApiModel
- 属性声明要添加@ApiModelProperty
- 属性声明要添加验证注解
- @NotNull
- @NotBlank
- @Min
- @Max
- @Range
- @Pattern
8.4 验证数据要使用@Valid注解
package com.example.emos.wx.controller.form;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
@ApiModel
@Data
public class TestSayHelloForm {
@NotBlank
@Pattern(regexp = "^[\\u4e00-\\u9fa5]{2,15}$",message = "不符合正则表达式")
@ApiModelProperty("姓名:2-15中文")
private String name;
}
9 抵御即跨站脚本(XSS)攻击
9.1 原因
- XSS攻击通常指的是通过利用网站系统保存数据的漏洞,通过巧妙的方法把恶意指令注入到网页,用户加载网页的时候就会自动执行恶意脚本。
- 如果黑客能在你的浏览器上执行javaScript,那么就能窃取Cookie或者Token
9.2 导入Hutool依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.14</version>
</dependency>
package com.example.emos.wx.config.xss;
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {}
public class XssFilter implements Filter {}
EmosWxApiApplication启动类添加@ServletComponentScan
9.3 对Http请求中的数据转义
- 设置过滤器
- 覆盖Http请求的方法
- HttpServletRequest是接口,各家服务器厂商会实现它
- 如果直接继承各厂商的请求父类,那么我们的程序就跟厂商绑定在一起
- HttpServletRequestWrapper类
- 使用了装饰器模式
- 装饰器封装了厂商的Request实现类
- 只需要覆盖Wrapper类的方法,就能做到覆盖厂商请求对象里方法
- 创建过滤器,把Request对象传入Wrapper对象
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了