发布:admin2025-10-06 18:54:04 7000条浏览分类:跨服战场
SSM整合
步骤
①Spring整合上Mybatis
通过Service层Dao层都注入Spring容器中
②引入配置SpringMVC
把Controller层注入SpringMVC容器中
③让web项目启动时自动读取Spring配置文件来创建Spring容器
可以使用ContextLoaderListener来实现Spring容器的创建。
为什么要用两个容器?
因为Controller如果不放在MVC容器中会没有效果,无法处理请求。而Service如果不放在Spring容器中,声明式事务也无法使用。
SpringMVC容器中的Controller需要依赖Service,怎么从Spring容器中获取到所依赖的Service对象?
Spring容器相当于是父容器,MVC容器相当于是子容器。子容器除了可以使用自己容器中的对象外还可以使用父容器中的对象。
模拟SpirnMVC子容器源码
子容器有父容器的地址,父容器没有子容器的地址
在ContextLoaderListener中,会在创建好spring容器后把容器存入servletContext域。这样在DispatcherServlet启动时,创建完SpringMVC容器后会从servletContext域中获取到Spring容器对象,设置其为父容器,这样子容器就能获取到父容器中的bean了。
所有配置代码
mysql初始化代码,版本为8.0
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis_db` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `mybatis_db`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`address` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
insert into `user`(`id`,`username`,`age`,`address`) values (1,'UZI',19,'上海'),(2,'PDD',25,'上海');
文件格式
依赖
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
applicationContext.xml
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/mybatis_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=123456
mybatis-config.xml
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
log4j.properties
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout
spring-mvc.xml
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
web.xml
"-//Java Community Process//DTD Web Application 3.0//EN"
"http://java.sun.com/dtd/web-app_3_0.dtd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
编写Controller,Service,Dao
书写步骤:controller类,service接口,service实现类,dao接口,dao映射文件,最后写sql语句
响应格式统一
我们要保证一个项目中所有接口返回的数据格式的统一。这样无论是前端还是移动端开发获取到我们的数据后都能更方便的进行统一处理。
所以我们定义以下结果封装类ResponseResult放入common包
package com.sangeng.common;
import com.fasterxml.jackson.annotation.JsonInclude;
//某个属性的值不为null才会转换成json
@JsonInclude(JsonInclude.Include.NON_NULL)
//任何接口都会返回一个ResponseResult对象,统一格式
public class ResponseResult
private Integer code; //状态码
private String msg; //操作成功或失败的提示信息
private T data; //返回的数据放到响应体中
//没有空参构造
public ResponseResult(Integer code, String msg) {
//增删改,没有查到的数据
this.code = code;
this.msg = msg;
}
public ResponseResult(Integer code, String msg, T data) {
//附带查到的数据
this.code = code;
this.msg = msg;
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
增删改查
根据id查找用户,查找所有用户,增加用户,删除用户,修改用户
Controller类
package com.sangeng.controller;
import com.sangeng.common.ResponseResult;
import com.sangeng.domain.User;
import com.sangeng.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class UserController {
@Autowired
private UserService userService;
//根据id查询用户
@GetMapping("/user/{id}")
public ResponseResult findById(@PathVariable("id") Integer id) {//从请求路径获取id
User user = userService.findById(id);
if(user == null) {
return new ResponseResult(500,"没有该用户");
}
return new ResponseResult(200,"操作成功",user);//会把这个转换成json,这里的200其实一般定义成枚举
}
//查询所有用户
@GetMapping("/user")
public ResponseResult findAll() {
List
return new ResponseResult(200,"操作成功",list);
}
//增加用户
@PostMapping("/user")
public ResponseResult insertUser(@RequestBody User user) {//从请求体中获取user(json格式)
userService.insertUser(user);
return new ResponseResult(200,"操作成功");
}
//删除用户
@DeleteMapping("/user/{id}")
public ResponseResult deleteUser(@PathVariable("id") Integer id) {
userService.deleteUser(id);
return new ResponseResult(200,"操作成功");
}
//修改用户
@PutMapping("/user")
public ResponseResult updateUser(@RequestBody User user){
userService.updateUser(user);
return new ResponseResult(200,"操作成功");
}
}
user类
package com.sangeng.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String username;
private Integer age;
private String address;
}
service接口
package com.sangeng.service;
import com.sangeng.domain.User;
import java.util.List;
public interface UserService {
User findById(Integer id);
List
void insertUser(User user);
void deleteUser(Integer id);
void updateUser(User user);
}
service实现类
package com.sangeng.service.impl;
import com.sangeng.dao.UserDao;
import com.sangeng.domain.User;
import com.sangeng.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User findById(Integer id) {
return userDao.findById(id);
}
@Override
public List
return userDao.findAll();
}
@Override
public void insertUser(User user) {
userDao.insertUser(user);
}
@Override
public void deleteUser(Integer id) {
userDao.deleteUser(id);
}
@Override
public void updateUser(User user) {
userDao.updateUser(user);
}
}
dao接口
package com.sangeng.dao;
import com.sangeng.domain.User;
import java.util.List;
public interface UserDao {
User findById(Integer id);
List
void insertUser(User user);
void deleteUser(Integer id);
void updateUser(User user);
}
dao映射xml文件
insert into user values(null,#{username},#{age},#{address})
update user set username = #{username},age = #{age},address = #{address} where id = #{id}
delete from user where id = #{id}
select * from user where id = #{id}
select * from user
分页查询用户
分页查询的结果除了要包含查到的用户数据外还要有当前页数,每页条数,总记录数这些分页数据。
所需依赖
mybatis-config.xml
需要进行分页数据的封装类PageResult
package com.sangeng.common;
import java.util.List;
public class PageResult
private Integer currentPage;//当前页数
private Integer pageSize;//每页条数
private Integer total;//总记录数
private List
public PageResult(Integer currentPage, Integer pageSize, Integer total, List
this.currentPage = currentPage;
this.pageSize = pageSize;
this.total = total;
this.data = data;
}
public Integer getCurrentPage() {
return currentPage;
}
public void setCurrentPage(Integer currentPage) {
this.currentPage = currentPage;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
public List
return data;
}
public void setData(List
this.data = data;
}
}
Controller方法
//分页查询
@GetMapping("/user/{pageSize}/{pageNum}")//每页显示条数,当前页数
public ResponseResult findByPage(@PathVariable("pageSize") Integer pageSize,@PathVariable("pageNum")Integer pageNum) {
PageResult pageResult = userService.findByPage(pageSize,pageNum);
return new ResponseResult(200,"操作成功",pageResult);
}
Service实现类
@Override
public PageResult findByPage(Integer pageSize, Integer pageNum) {
PageHelper.startPage(pageNum, pageSize);
List
PageInfo pageInfo = new PageInfo(list);
PageResult pageResult = new PageResult(pageInfo.getPageNum(),pageInfo.getPageSize(),(int)pageInfo.getTotal(),list);
return pageResult;
}
执行(每页显示1条,查询第2页)
查询结果
异常统一处理
我们可以使用@ControllerAdvice实现对异常的统一处理。让异常出现时也能返回响应一个JSON。
自定义MyControllerAdvice类,接收所有异常
package com.sangeng.exception;
import com.sangeng.common.ResponseResult;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class MyControllerAdvice {
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseResult handlerException(Exception e){
return new ResponseResult(500, e.getMessage());
}
}
遇到异常会把500和异常信息放到响应体中
除0异常
拦截器
自定义MyHandlerInterceptor类
package com.sangeng.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
spring-mvc.xml配置
声明式事务@Transactional
只能对service方法使用
@Transactional
@Override
public void test() {
userDao.insertUser(new User(null,"test1",11,"aa"));
System.out.println(1/0);//除0异常
userDao.insertUser(new User(null,"test2",12,"bb"));
}
AOP
自定义切面类
package com.sangeng.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAspect {
@Pointcut("execution(* com.sangeng.service..*.*(..))")
public void pt(){
}
@Before("pt()")
public void before(){
System.out.println("before");
}
}
注意
只能对service方法进行增强,切点如果改成controller包下,AOP无效
不能对Controller进行增强,因为切面类只会被放入父容器spring,
这个是放入Spring容器中,被Spring容器扫描
而我们的Controller是在子容器中的。父容器不能访问子容器(子容器有父容器的地址,父容器没有子容器的地址)
我们如果需要对Controller进行增强,使用拦截器也会更加的好用。
拦截器其实就是AOP的封装,注意不要掉入陷阱