• 首页
  • 跨服战场
  • 【SSM】2025最新SSM整合,包含全部xml配置代码,手把手带你走一遍后端开发完整流程

【SSM】2025最新SSM整合,包含全部xml配置代码,手把手带你走一遍后端开发完整流程

发布: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">

4.0.0

com.sangeng

SSM

war

1.0-SNAPSHOT

SSM Maven Webapp

http://maven.apache.org

junit

junit

4.12

test

org.springframework

spring-context

6.2.0

org.aspectj

aspectjweaver

1.9.7

org.springframework

spring-jdbc

6.2.0

org.mybatis

mybatis-spring

3.0.3

org.mybatis

mybatis

3.5.10

log4j

log4j

1.2.17

com.github.pagehelper

pagehelper

4.0.0

mysql

mysql-connector-java

8.0.33

com.alibaba

druid

1.2.8

org.springframework

spring-test

6.2.0

test

org.projectlombok

lombok

1.18.30

provided

javax.servlet

javax.servlet-api

3.1.0

provided

javax.servlet.jsp

jsp-api

2.1

provided

org.springframework

spring-webmvc

5.1.9.RELEASE

com.fasterxml.jackson.core

jackson-databind

2.9.0

commons-fileupload

commons-fileupload

1.4

SSM

org.apache.tomcat.maven

tomcat7-maven-plugin

2.1

80

/

utf-8

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">

Archetype Created Web Application

contextConfigLocation

classpath:applicationContext.xml

org.springframework.web.context.ContextLoaderListener

DispatcherServlet

org.springframework.web.servlet.DispatcherServlet

contextConfigLocation

classpath:spring-mvc.xml

1

DispatcherServlet

/

CharacterEncodingFilter

org.springframework.web.filter.CharacterEncodingFilter

encoding

UTF-8

CharacterEncodingFilter

/*

编写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 list = userService.findAll();

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 findAll();

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 findAll() {

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 findAll();

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}

分页查询用户

分页查询的结果除了要包含查到的用户数据外还要有当前页数,每页条数,总记录数这些分页数据。

所需依赖

com.github.pagehelper

pagehelper

4.0.0

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 data;

public PageResult(Integer currentPage, Integer pageSize, Integer total, List data) {

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 getData() {

return data;

}

public void setData(List data) {

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 list = userDao.findAll();

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的封装,注意不要掉入陷阱