JavaWeb后端架构系统学习笔记
一、整体架构流程
1.1 请求-响应路径
流程说明:
请求从浏览器发出,依次经过 过滤器 → 拦截器 → Controller → Service → Dao → 数据库
响应路径为反向流程:数据库 → Dao → Service → Controller → 拦截器 → 过滤器 → 浏览器
1.2 分层架构解析
分层架构 是JavaWeb后端开发的核心设计模式,它将复杂的系统划分为多个独立层级,每个层级专注于特定功能,显著降低了系统耦合度,提高了可维护性和扩展性 。
| 层级 | 职责 | 技术栈 | 与相邻层级关系 |
|---|---|---|---|
| 过滤器层 | 预处理/后处理所有请求 | Servlet API、Filter | 接收浏览器请求,传递给拦截器层 |
| 拦截器层 | 拦截特定请求,执行横切关注点 | Spring Interceptor | 接收过滤器处理后的请求,传递给Controller层 |
| Controller层 | 接收前端请求,调用业务逻辑 | Spring MVC、@RestController | 接收拦截器处理后的请求,调用Service层 |
| Service层 | 处理核心业务逻辑 | Spring Service、@Transactional | 接收Controller请求,协调多个Dao操作 |
| Dao层 | 数据持久化操作 | MyBatis、JPA、JDBC | 执行Service层的数据访问指令 |
| 数据库层 | 存储和管理数据 | MySQL、PostgreSQL | 接收并执行Dao层的SQL语句 |
1.3 架构优势
分层架构提供了以下关键优势:
- 职责清晰:每个层级只关注特定功能,避免代码混杂 。
- 解耦性强:层级间通过接口通信,降低模块依赖 。
- 扩展性高:新增功能只需修改对应层级,不影响其他模块 。
- 复用性好:通用组件(如工具类、实体类)可跨层级复用 。
- 维护简便:问题定位和修复集中在特定层级,效率显著提高。
二、核心组件解析
2.1 过滤器(Filter)
2.1.1 概念与作用
过滤器 是基于Servlet规范的组件,对所有HTTP请求进行预处理和响应的后处理 。它不依赖具体业务逻辑,是Web应用的第一道防线。
2.1.2 常见用途
- 编码设置:统一处理请求编码(如UTF-8)
- 日志记录:记录请求路径、参数和响应时间
- 安全防护:防止XSS攻击、CSRF攻击等
- 请求头处理:添加或修改HTTP头信息
- 权限校验:基础权限验证(如未登录用户重定向)
2.1.3 实现方式
通过实现Filter接口并配置web.xml或使用注解注册过滤器:
java
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
req.setCharacterEncoding("UTF-8");
res.setCharacterEncoding("UTF-8");
chain.doFilter(req, res);
}
// 初始化和销毁方法略
}
在web.xml中配置:
xml
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>com.example过滤器 EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.2 拦截器(Interceptor)
2.2.1 概念与作用
拦截器 是Spring框架提供的组件,拦截特定请求,执行横切关注点 。与过滤器不同,拦截器仅作用于Spring管理的请求 ,更灵活且业务关联性更强。
2.2.2 与过滤器的区别
| 特性 | 过滤器 | 拦截器 |
|---|---|---|
| 规范 | Servlet规范 | Spring框架层 |
| 作用范围 | 所有请求 | Spring管理的请求 |
| 配置方式 | web.xml或注解 | Spring配置类或注解 |
| 执行时机 | 在Servlet容器层面 | 在Spring MVC层面 |
| 扩展性 | 较低 | 较高 |
2.2.3 常见用途
- 登录状态检查:结合Cookie/Session或JWT验证用户身份
- 权限控制:基于角色(RBAC)或属性(ABAC)验证访问权限
- 性能监控:记录方法执行时间,分析系统瓶颈
- 请求参数校验:验证请求参数格式和有效性
- 日志记录:记录业务方法执行日志
2.2.4 实现方式
通过实现HandlerInterceptor接口并注册到Spring容器 :
java
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 权限校验逻辑
return true; // 放行请求
}
}
在Spring配置类中注册拦截器:
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**") // 拦截所有API请求
.excludePathPatterns("/login", "/register"); // 排除登录注册接口
}
}
2.3 Controller层
2.3.1 职责与特点
Controller层 是用户请求的入口,负责接收前端请求、调用业务逻辑并返回响应结果 。它不处理业务逻辑 ,仅作为请求的中转站。
2.3.2 技术栈与注解
主要技术栈:Spring MVC、Spring Boot、RESTful API设计
常用注解:
java
@RestController // 表示这是一个RESTful控制器,返回数据直接序列化为JSON
@RequestMapping("/api/user") // 定义基础请求路径
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}") // 处理GET请求
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
return ResponseEntity.ok(user);
}
@PostMapping // 处理POST请求
public ResponseEntity<User> createUser(@Valid @RequestBody UserCreateRequest request) {
User user = userService.createUser(request);
return ResponseEntity.created(URI.create("/api/user/" + user.getId())).body(user);
}
}
2.3.3 参数接收方式
Spring MVC提供了多种参数接收方式,根据需求灵活选择:
- @RequestParam:接收查询参数或请求体中的简单参数
- @RequestBody:接收请求体中的复杂对象(如JSON数据)
- @PathVariable:接收URL中的动态路径参数
- @CookieValue:接收请求中的Cookie值
- @SessionAttribute:接收Session中的属性值
2.4 Service层
2.4.1 职责与特点
Service层 是业务逻辑的核心,封装系统的核心业务规则和流程 。它通常不直接与数据库交互 ,而是通过调用Dao层实现数据访问 。Service层是事务管理的主要场所 ,保证业务操作的原子性。
2.4.2 技术栈与注解
主要技术栈:Spring Service、事务管理、AOP
常用注解:
java
@Service // 表示这是一个业务服务类
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional // 声明事务管理
public void updateUser(User user) {
userMapper.update(user);
// 其他业务操作...
}
}
2.5 Dao层(Data Access Object)
2.5.1 职责与特点
Dao层 负责与数据库交互 ,执行数据的增删改查操作 。它不包含业务逻辑 ,仅专注于数据访问 。在Spring框架中,通常通过JDBC、MyBatis或JPA实现。
2.5.2 实现方式
MyBatis实现:
java
@Mapper // 声明这是一个MyBatis映射接口
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User getUserById(Long id);
@Update("UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}")
void updateUser(User user);
}
JPA实现:
java
@Repository // 声明这是一个数据访问层组件
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByName(String name);
List<User> findByAgeLessThanEqual(Integer maxAge);
}
三、核心技术栈支持
3.1 IOC(Inversion of Control)控制反转
3.1.1 概念
IOC是Spring框架的核心思想 ,将对象的创建和管理权从程序员转移到Spring容器 。对象的依赖关系通过容器自动装配 ,而非手动创建。
3.1.2 实现机制
Spring容器通过反射机制 和工厂模式实现IOC :
- 读取配置:从XML或注解中获取Bean定义
- 实例化对象:根据类信息动态创建实例
- 依赖注入:根据依赖关系自动注入其他Bean
- 管理生命周期:控制Bean的初始化和销毁时机
3.1.3 容器类型
Spring提供了两种主要IOC容器:
| 容器类型 | 特点 | 适用场景 |
|---|---|---|
| BeanFactory | 基础容器,延迟加载,轻量级 | 资源受限环境,如移动端 |
| ApplicationContext | 扩展型容器,支持预初始化单例、事件机制等 | 企业级应用,如Web应用 |
3.2 DI(Dependency Injection)依赖注入
3.2.1 概念
DI是IOC的具体实现方式 ,通过容器自动将对象依赖注入到目标对象中 。它解决了传统开发中手动管理依赖的繁琐问题 ,使代码更简洁、可维护性更高。
3.2.2 注入方式
Spring支持两种主要依赖注入方式:
构造器注入 :通过构造方法传递依赖,强制依赖不可变 ,适合强制依赖场景 。
java
@Service
public class UserService {
private final IDEAcess Dal;
@Autowired
public UserService(IDataAccess Dal) {
this.Dal = Dal;
}
}
设值注入 :通过setter方法或字段注解注入依赖,灵活性更高 ,适合可选依赖场景 。
java
@Service
public class UserService {
@Autowired
private IDEAcess Dal;
}
3.2.3 依赖管理
通过**@Autowired或@Resource**注解实现自动装配 :
java
@Autowired
private IDEAcess Dal; // 自动注入IDEAcess类型的Bean
3.3 AOP(Aspect Oriented Programming)面向切面编程
3.3.1 概念
AOP是Spring框架的另一个核心特性 ,通过横切面(Aspect)将通用功能(如日志、事务)与业务逻辑分离 。它解决了传统开发中重复代码的问题 ,使代码更简洁、可维护性更高。
3.3.2 通知类型
Spring AOP支持五种主要通知类型:
| 通知类型 | 注解 | 执行时机 | 典型应用场景 |
|---|---|---|---|
| 前置通知 | @Before | 目标方法执行前 | 方法调用前记录日志 |
| 后置通知 | @After | 目标方法执行后 | 方法调用后释放资源 |
| 返回后通知 | @AfterReturning | 方法正常返回后 | 方法成功执行后的记录 |
| 异常通知 | @AfterThrowing | 方法抛出异常后 | 方法异常时的错误处理 |
| 环绕通知 | @Around | 完全围绕目标方法 | 事务管理、方法执行计时 |
3.3.3 切点表达式
切点表达式 用于定义哪些方法会被AOP拦截 :
java
@Aspect
@Component
public class LoggingAspect {
// 定义切点:拦截所有Service层的方法
@Pointcut("execution(* com.example.service.*.*(..))")
private void serviceMethods() {}
// 定义切点:拦截所有带有@Log注解的方法
@Pointcut("@annotation(com.example.annotation.Log)")
private void logAnnotatedMethods() {}
// 使用切点
@Before("serviceMethods() || logAnnotatedMethods()") // 拦截Service层方法或带有@Log注解的方法
public void logBefore(JoinPoint joinPoint) {
String method = joinPoint.getSignature().getName();
String args = Arrays.toString(joinPoint.getArgs());
System.out.println("方法调用前: " + method + " 参数: " + args);
}
}
3.3.4 实际应用场景
AOP在JavaWeb中的典型应用:
- 日志记录:记录方法执行前后的信息
- 事务管理:通过@Around通知实现事务控制
- 权限控制:在方法执行前验证用户权限
- 性能监控:记录方法执行时间,分析系统瓶颈
- 异常处理:统一处理方法抛出的异常
3.4 事务管理
3.4.1 概念
事务管理 确保一系列数据库操作要么全部成功,要么全部失败 ,保证数据的一致性和完整性 。在JavaWeb中,通常通过Spring的声明式事务管理实现。
3.4.2 传播行为
事务传播行为 定义方法调用时如何处理事务 :
| 传播行为 | 注解值 | 行为说明 | 适用场景 |
|---|---|---|---|
| Required | 传播行为值 | 支持当前事务,无则新建 | 大多数业务方法 |
| RequiresNew | 传播行为值 | 挂起当前事务,新建独立事务 | 需要独立事务的方法 |
| Never | 传播行为值 | 禁止事务,若存在则抛异常 | 必须非事务的方法 |
| Mandatory | 传播行为值 | 必须在事务中执行 | 必须事务的方法 |
| Support | 传播行为值 | 支持事务但不强制 | 可选事务的方法 |
3.4.3 隔离级别
事务隔离级别 定义事务之间如何隔离 ,平衡并发性能与数据一致性 :
| 隔离级别 | 注解值 | 特点 | 适用场景 |
|---|---|---|---|
| 默认 | 默认值 | 使用数据库默认级别(通常为READ_COMMITTED) | 大多数场景 |
| 读未提交 | 隔离级别值 | 允许脏读,但并发性能高 | 对一致性要求不高的场景 |
| 读已提交 | 隔离级别值 | 禁止脏读,允许不可重复读 | 一般业务场景 |
| 可重复读 | 隔离级别值 | 禁止脏读和不可重复读,但允许幻读 | 需要高一致性的场景 |
| 序列化 | 隔离级别值 | 串行化事务,完全隔离但性能差 | 对一致性要求极高的场景 |
3.4.4 事务管理实现
通过@Transactional注解实现声明式事务管理 :
java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional propagation =传播行为, isolation =隔离级别)
public void updateUser(User user) {
userMapper.update(user);
// 其他业务操作...
}
}
3.5 全局异常处理
3.5.1 概念
全局异常处理 将异常捕获和处理逻辑集中管理 ,避免在每个方法中重复编写异常处理代码 。它提高了代码的复用性和可维护性。
3.5.2 实现方式
通过@ControllerAdvice注解实现 :
java
@ControllerAdvice
@RestController
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
// 捕获参数缺失异常
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public Result handleMissingParam(MissingServletRequestParameterException ex) {
logger.error("缺少必要参数: {}", ex.getMessage());
return Result.error(400, "缺少必要参数", ex.getMessage());
}
// 捕获空指针异常
@ExceptionHandler(NullPointerException.class)
public Result handleNullPointerException(NullPointerException ex) {
logger.error("空指针异常: {}", ex.getMessage());
return Result.error(500, "系统内部错误", "空指针异常");
}
// 捕获自定义业务异常
@ExceptionHandler(BusinessException.class)
public Result handleBusinessException(BusinessException ex) {
logger.error("业务异常: {}", ex.getMessage());
return Result.error(ex码, ex信息, ex详情);
}
}
3.5.3 异常封装
建议将异常封装为统一格式 :
json
{
"code": 状态码(数字),
"msg": 中文解析(字符串),
"data": 返回数据(对象),
"traceId": 请求追踪ID(字符串)
}
四、辅助功能模块
4.1 Cookie & Session
4.1.1 概念
Cookie 是存储在客户端的小型文本数据 ,通常用于标识用户身份 。Session 是服务器端存储的用户状态信息 ,与Cookie配合使用实现用户身份保持 。
4.1.2 配置与使用
Cookie操作:
java
// 设置Cookie
@GetMapping("/set-cookie")
public String setCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("user_token", "abc123");
cookie.setMaxAge(3600); // 有效期1小时
cookie.setPath("/"); // 全站有效
cookie.setHttpOnly(true); // 防止XSS攻击
response.addCookie cookie);
return "Cookie设置成功";
}
// 读取Cookie
@GetMapping("/read-cookie")
public String readCookie(@CookieValue(name = "user_token", defaultValue = "") String token) {
if (token.isEmpty()) {
return "未找到用户Token";
}
return "当前用户Token: " + token;
}
// 删除Cookie
@GetMapping("/delete-cookie")
public String deleteCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("user_token", null);
cookie.setMaxAge(0); // 立即过期
response.addCookie cookie);
return "Cookie已删除";
}
Session配置:
在application.properties中设置Session超时时间:
properties
server.servlet.session.timeout=30m # Session有效期30分钟
Session操作:
java
// 设置Session属性
@GetMapping("/set-session")
public String setSession(HttpServletRequest request) {
HttpSession session = request.getSession();
session.setAttribute("cart", Arrays.asList("item1", "item2"));
return "Session数据已存储";
}
// 读取Session属性
@GetMapping("/get-session")
public String getSession(HttpServletRequest request) {
(HttpSession session = request sessions);
List<String> cart = (List<String>) session.getAttribute("cart");
return "购物车内容: " + (cart != null ? cart : "空");
}
4.1.3 分布式Session管理
在微服务架构中,推荐使用Redis实现分布式Session共享 :
依赖引入:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
配置文件:
properties
spring redis host=localhost
spring redis port=6379
spring session store-type=redis
启用Redis Session:
java
@EnableRedisHttpSession
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4.2 JWT(JSON Web Token)
4.2.1 概念
JWT是一种基于令牌的无状态认证方案 ,将用户信息加密后存储在令牌中 ,服务端无需存储Session 。它特别适合分布式系统和移动端应用。
4.2.2 JWT结构
一个标准的JWT由三个部分组成:
- Header(头部):声明令牌类型和加密算法
- Payload(负载):存储用户信息和声明(如过期时间)
- Signature(签名):验证令牌完整性和来源
三部分之间用英文句点分隔,格式为:
Header base64Url编码 . Payload base64Url编码 . Signature
4.2.3 JWT工具类实现
使用JJWT库生成和解析JWT :
java
@Component
public class JWTUtil {
// 从配置文件获取密钥
@Value("${jwt秘密}")
private String secret;
// 生成JWT
public String generateToken(Map<String, Object> claims) {
return JWT.create()
.withClaim("个人信息", claims)
.withExpiresAt(new Date(System.currentTimeMillis() + 3600000)) // 1小时后过期
.sign(Algorithm.HMAC256(secret));
}
// 解析JWT
public DecodedJWT decodeToken(String token) {
try {
return JWT.decode(token);
} catch (JWTVerificationException ex) {
throw new JWTDecodeException("无效的Token", ex);
}
}
// 验证JWT有效性
public boolean validateToken(String token) {
try {
DecodedJWT decodedJWT = decodeToken(token);
return !decodedJWT.is糖过期();
} catch (JWTDecodeException ex) {
return false;
}
}
// 获取JWT中的用户信息
public Map<String, Object> getUserInfo(String token) {
DecodedJWT decodedJWT = decodeToken(token);
return decodedJWT.getClaim("个人信息").asMap();
}
}
4.2.4 JWT拦截器实现
自定义拦截器验证JWT令牌 :
java
@Component
public class JWTInterceptor implements HandlerInterceptor {
@Autowired
private JWTUtil jwtUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 从请求头获取Token
String token = request.getHeader("Authorization");
if (token == null) {
// 从请求参数获取Token
token = request.getParameter("token");
}
// 验证Token
if (token == null || !jwtUtil.validateToken(token)) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json");
try {
response.getWriter().write JSON格式的错误响应);
} catch (IOException e) {
e.printStackTrace();
}
return false; // 拒绝访问
}
// 将用户信息存入请求属性
Map<String, Object> userInfo = jwtUtil.getUserInfo(token);
request.setAttribute("个人信息", userInfo);
return true; // 放行请求
}
}
4.2.5 安全最佳实践
JWT安全配置建议:
- 密钥管理:使用环境变量存储JWT密钥,避免硬编码
- IP绑定:在Payload中设置客户端IP,验证时检查IP一致性
- 加密算法:使用AES等强加密算法保护Token
- 设置合理过期时间:根据业务场景设置Token有效期
- 定期更新密钥:定期更换JWT签名密钥,降低密钥泄露风险
4.3 阿里云OSS
4.3.1 概念
阿里云OSS是对象存储服务 ,用于存储和管理非结构化数据(如图片、视频) 。它提供了高可用、高可靠的存储解决方案 ,适合Web应用的静态资源存储。
4.3.2 配置与使用
依赖引入:
xml
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.19.0</version>
</dependency>
配置文件:
properties
# 阿里云OSS配置
oss endpoint=oss-cn-hangzhou.aliyuncs.com
oss bucket name=my-bucket
oss access key id=YOUR_ACCESS_KEY_ID
oss access key secret=YOUR_ACCESS_KEY_SECRET
文件上传示例:
java
@RestController
@RequestMapping("/api/oss")
public class OSSController {
@Value("${oss endpoint}")
private String endpoint;
@Value("${oss bucket name}")
private String bucketName;
@Value("${oss access key id}")
private String accessKeyId;
@Value("${oss access key secret}")
private String accessKeySecret;
@PostMapping("/upload")
public Result uploadFile(@RequestParam("file") MultipartFile file) {
try {
// 创建OSS客户端
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
// 上传文件
String key = "images/" + UUID.randomUUID().toString() + "." + file.getExtension();
ossClient.putObject(bucketName, key, file.getInputStream());
// 关闭客户端
ossClient.close();
// 返回文件URL
String url = "https://"+ bucketName + "." + endpoint + "/" + key;
return Result.success(url);
} catch (IOException e) {
e.printStackTrace();
return Result.error("文件上传失败");
}
}
}
文件下载示例:
java
@GetMapping("/download/{key}")
public void downloadFile(HttpServletRequest request, HttpServletResponse response, @PathVariable String key) {
try {
// 创建OSS客户端
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
// 获取文件信息
ObjectListing listing = ossClient.listObjects (bucketName, key);
OSSObject ossObject = ossClient.getObject (bucketName, key);
// 设置响应头
response.reset();
response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(key, "UTF-8"));
response.addHeader("Content-Type", ossObject.getMetadata().getContentType());
response.addHeader("Content-Length", String.valueOf(ossObject.getMetadata(). ContentLength));
// 将文件流写入响应
IOUtils.copy(ossObject.getObjectContent(), response.getOutputStream());
// 关闭客户端
ossClient.close();
} catch (Exception e) {
e.printStackTrace();
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
}
4.3.3 安全配置建议
OSS安全配置建议:
- 最小权限原则:为RAM用户分配最小必要权限
- 开启防盗链:防止他人直接访问OSS资源
- 设置合理的过期时间:为临时访问链接设置过期时间
- 使用HTTPS:确保数据传输安全
- 定期轮换密钥:降低密钥泄露风险
4.4 MyBatis
4.4.1 概念
MyBatis是持久层框架 ,通过XML或注解配置SQL语句 ,简化了JDBC操作 。它提供了灵活的数据库操作能力 ,适合复杂SQL场景。
4.4.2 整合Spring Boot
依赖引入:
xml
<dependency>
<groupId>org mybatis spring. boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
配置文件:
properties
# MyBatis配置
mybatis mapper locations=classpath:mapper/*.xml
mybatis typealiases package=com.example entity
mybatis configuration map underying column with骆驼命名法=true
动态SQL示例:
xml
<select id="getUserByCondition" resultType="User">
SELECT * FROM user
<where>
<if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="age != null">
AND age = #{age}
</if>
<if test="status != null">
AND status = #{status}
</if>
</where>
ORDER BY id DESC
</select>
注解方式:
java
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User getUserById(Long id);
@Insert("INSERT INTO user (name, age) VALUES (#{name}, #{age})")
@Options(keyProperty = "id", useActualParamName = true)
void insertUser(User user);
@Update("UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}")
void updateUser(User user);
@Delete("DELETE FROM user WHERE id = #{id}")
void.deleteUser(Long id);
}
4.4.4 安全配置建议
MyBatis安全配置建议:
- 使用参数化查询 :避免SQL注入,使用
#{param}而非${param} - 开启SQL日志:调试阶段开启,生产环境关闭
- 设置合理的超时时间:防止长时间等待导致资源浪费
- 使用连接池:如HikariCP,提高数据库连接效率
- 定期检查SQL性能:使用Explain分析慢查询
五、架构总结与最佳实践
5.1 架构总结
JavaWeb后端架构具有以下核心特点:
- 分层清晰:从浏览器到数据库的明确请求-响应路径
- 职责分明:各层专注自身任务,降低耦合
- 扩展性强:易于引入新功能(如Redis缓存、消息队列)
- 安全可控:通过拦截器和JWT实现权限控制
- 性能可调:通过缓存、索引优化提升系统性能
- 可维护性高:分层设计使问题定位和修复更高效
5.2 最佳实践建议
5.2.1 模块化设计
按功能+层次组合拆分模块 :
text
项目名/
├── parent/ # 父工程,管理依赖和配置
├── common/ # 公共模块
│ ├── config/ # 配置文件
│ ├── utils/ # 工具类
│ └── entity/ # 实体类
├── order/ # 订单模块
│ ├── controller/
│ ├── service/
│ └── mapper/
├── user/ # 用户模块
│ ├── controller/
│ ├── service/
│ └── mapper/
└── web/ # Web入口模块
5.2.2 安全实践
安全是JavaWeb架构的核心考量:
- 输入验证:对所有用户输入进行验证,防止注入攻击
- 权限控制:实现细粒度权限管理,如RBAC或ABAC模型
- 加密传输:使用HTTPS确保数据传输安全
- 定期安全审计:检查系统漏洞和配置问题
- 使用安全框架:如Spring Security、Shiro等
5.2.3 性能优化
性能优化是JavaWeb架构的关键:
-
缓存策略:使用Redis缓存高频访问数据
java@Cacheable(value = "users", key = "#id") public User getUserById(Long id) { return userMapper.getUserById(id); } -
数据库优化:合理设计索引,避免全表扫描
sqlCREATE INDEX idx_user_name ON user(name); -
异步处理:使用消息队列处理耗时操作
java@Async public void sendEmail(User user, String content) { // 发送邮件逻辑 } -
连接池管理:配置合理的数据库连接池参数
propertiesspring.datasource.hikari.maximum-pool-size=20 spring.datasource.hikari.minimum-idle=5 -
监控与日志:使用ELK栈或Spring Boot Actuator监控系统状态
5.2.4 部署实践
现代部署实践提升系统可用性:
-
容器化部署:使用Docker容器化应用
dockerfileFROM openjdk:17-jre-slim VOLUME /tmp COPY target/*.jar app.jar ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] -
微服务架构:使用Spring Cloud实现微服务
java@SpringBootApplication @EnableEurekaClient // 服务注册 public class User服务中心 { public static void main(String[] args) { SpringApplication.run(User服务中心.class, args); } } -
配置中心:使用Spring Cloud Config实现动态配置
properties# 配置中心地址 spring.config尿服务器=http://config-server:8888 -
服务网关:使用Spring Cloud Gateway实现统一入口
yamlspring: cloud: gateway: routes: - id: user-service uri: lb://USER-SERVICE predicates: - Path=/api/user/** -
断路器模式:使用Hystrix或Resilience4j实现容错
java@HystrixCommand(fallbackMethod = "fallback") public User getUserById(Long id) { return userMapper.getUserById(id); } public User fallback(Long id) { // 回退逻辑 return new User(id, "匿名用户", 0); }
5.2.5 监控与维护
完善的监控体系是架构成功的关键:
-
健康检查:使用Spring Boot Actuator提供健康检查端点
propertiesmanagement端点 enabled end points=health,info,env management端点暴露端点=web -
日志管理:使用ELK栈集中管理日志
java@Value("${log.level}") private String logLevel; @Bean public滚筒文件日志配置配置() { Logback滚筒文件日志配置配置 = new滚筒文件日志配置(); configuration.setFile(logPath + "/app.log"); configuration.set contexts contexts); configuration.set contexts contexts); return configuration; } -
性能监控:使用Prometheus+Grafana监控系统性能
java@Bean public米特里克斯() { return new米特里克斯(); } @Bean public斯普林米特里克斯配置() { SpringMetricsConfig config = new SpringMetricsConfig(); config.set contexts contexts); return config; } -
自动化测试:使用JUnit5、Mockito进行单元测试和集成测试
java@SpringBootTest @AutoConfiguration类 class UserServiceTest { @Autowired private UserService userService; @MockBean private UserMapper userMapper; @Test void测试获取用户信息() { // 模拟数据库返回 User user = new User(1L, "测试用户", 25); when(userMapper.getUserById(1L)).thenReturn(user); // 调用服务方法 User result = userService.getUserById(1L); // 验证结果 assertEquals("测试用户", result.getName()); } } -
持续集成:使用Jenkins或GitHub Actions实现自动化构建和测试
yamlname: Java CI with Maven on: push: branches: [main] pull_request: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up JDK 17 uses: actions/setup-java@v2 with: java-version: '17' distribution: 'temurin' - name: Build with Maven run: mvn clean package -DskipTests - name: Run tests run: mvn test
5.3 架构演进路径
JavaWeb架构可随系统规模发展而演进:
- 单体架构:小型项目,所有功能集中在单一应用
- 模块化单体架构:中型项目,按功能或层次拆分模块
- 微服务架构:大型分布式系统,按业务拆分服务
- 云原生架构:超大规模系统,使用容器化和Serverless技术
六、补充知识
6.1 分层架构设计原则
分层架构应遵循以下核心原则:
- 高内聚:每个层级内部功能紧密相关,减少内部冗余
- 低耦合:层级间依赖最小化,通过接口通信
- 单一职责:每个层级只关注单一功能,避免职责混杂
- 可替换性:层级可独立替换,如替换数据库或认证方式
- 清晰边界:层级间有明确的接口定义和数据格式
6.2 模块间依赖管理
模块间依赖应遵循以下规则:
- 单向依赖:层级间依赖方向一致,避免循环依赖
- 接口隔离:上层通过接口调用下层,而非直接依赖实现类
- 依赖版本统一:使用父工程的dependencyManagement统一管理依赖版本
- 避免过度拆分:模块粒度适中,避免因拆分过多增加维护成本
- 考虑未来扩展:预留接口和扩展点,便于后续功能扩展
6.3 代码规范与风格
良好的代码规范是架构成功的基础:
- 命名规范 :清晰表达含义,如
User服务中心、UserMapper - 注释规范:关键逻辑添加注释,但避免过度注释
- 异常处理:统一异常处理策略,避免重复代码
- 日志规范:使用统一的日志框架和格式
- 代码复用:提取公共代码为工具类或父类,提高复用性
七、常见问题与解决方案
7.1 依赖冲突问题
现象:编译或运行时出现类冲突
解决方案:
- 使用
mvn dependency:tree分析依赖树 - 通过
<exclusion>排除冲突依赖 - 在父工程
<dependencyManagement>中统一版本
7.2 构建顺序问题
现象:模块间依赖关系导致构建失败
解决方案:
- 在聚合工程
<modules>标签中声明模块顺序 - 确保子模块pom.xml正确声明依赖关系
- 使用
<dependency>标签明确指定依赖范围
7.3 事务管理问题
现象:事务未按预期提交或回滚
解决方案:
- 确保Service层方法使用
@Transactional注解 - 检查事务传播行为和隔离级别设置
- 避免在Service层内部调用其他Service方法,使用AOP或代理模式
7.4 JWT安全问题
现象:Token被截获或篡改
解决方案:
- 使用强加密算法(如AES)保护Token
- 实现Token IP绑定,验证请求IP与Payload中的IP是否一致
- 设置合理的Token过期时间,避免长期有效
- 定期轮换签名密钥,降低密钥泄露风险
- 实现Token黑名单机制,支持主动失效
7.5 数据库性能问题
现象:查询速度慢,系统响应延迟高
解决方案:
- 使用Explain分析慢查询
- 合理设计索引,避免全表扫描
- 使用缓存(如Redis)减少数据库访问次数
- 分库分表处理大数据量场景
- 使用连接池管理数据库连接
八、面试高频考点
8.1 分层架构设计
高频问题:
- 请描述JavaWeb的分层架构及其各层职责
- 过滤器和拦截器的区别是什么?
- Controller层为什么不应该包含业务逻辑?
回答要点:
- 分层架构包括:浏览器层、过滤器层、拦截器层、Controller层、Service层、Dao层、数据库层
- 过滤器基于Servlet规范,作用于所有请求;拦截器基于Spring框架,仅拦截Spring管理的请求
- Controller层负责接收请求和返回响应,业务逻辑应放在Service层,保持职责清晰
8.2 IOC/DI原理
高频问题:
- 什么是IOC?其核心思想是什么?
- DI和IOC的关系是什么?
- Spring的依赖注入有哪些方式?
回答要点:
- IOC(控制反转)将对象创建和管理权从程序员转移到容器
- DI(依赖注入)是IOC的具体实现方式,通过容器自动注入依赖
- Spring支持设值注入(setter注入)和构造器注入两种主要方式
8.3 AOP应用
高频问题:
- 什么是AOP?与OOP的区别是什么?
- Spring AOP支持哪些通知类型?
- 如何实现一个日志记录的AOP切面?
回答要点:
- AOP通过横切面将通用功能与业务逻辑分离,解决OOP中重复代码问题
- Spring AOP支持前置通知、后置通知、返回后通知、异常通知和环绕通知
- 使用@Aspect注解定义切面,@Before、@After等注解定义通知,@Pointcut定义切点
8.4 事务管理
高频问题:
- Spring事务传播行为有哪些?
- 事务隔离级别如何选择?
- 如何保证分布式系统中的事务一致性?
回答要点:
- 常见传播行为包括REQUIRED、REQUIRES_NEW、NEVER等
- 隔离级别根据业务需求选择,默认为READ_COMMITTED
- 分布式事务可使用TCC、Saga或Seata等方案实现
8.5 JWT认证
高频问题:
- JWT认证原理是什么?
- JWT与Session认证的区别是什么?
- 如何保证JWT的安全性?
回答要点:
- JWT将用户信息加密后存储在令牌中,服务端无需存储Session
- JWT适合分布式系统和移动端,Session适合传统Web应用
- JWT安全性通过密钥管理、IP绑定、加密算法和合理过期时间保证
8.6 分布式架构
高频问题:
- 微服务架构有哪些优势?
- 如何实现微服务间的通信?
- 如何解决微服务中的配置管理问题?
回答要点:
- 微服务架构优势包括服务自治、高扩展性、技术栈灵活等
- 微服务通信可通过REST API、RPC(如Dubbo)或消息队列(如RabbitMQ)实现
- 使用Spring Cloud Config或Nacos实现微服务配置中心
九、总结
JavaWeb后端架构是构建企业级应用的基础 ,掌握其核心组件和技术栈对开发高质量应用至关重要 。分层架构通过职责分离和接口定义,提供了良好的可维护性和扩展性 。IOC/DI和AOP等Spring核心功能,使开发更加简洁高效 。随着系统规模扩大,架构可从单体逐步演进到微服务和云原生架构 ,适应不同业务需求。
在实际开发中,应根据项目规模和团队能力选择合适的架构复杂度 。小型项目可采用模块化单体架构 ,中大型项目推荐使用微服务架构 。无论选择哪种架构,都应遵循分层设计原则,确保系统清晰、安全、高效 。