服务器启动阶段处理
分析服务器启动阶段都都需要初始化什么?
1.初始化Spring容器
- 组件扫描包下的类纳入IOC容器管理
- 创建视图解析器对象
- 创建所有的拦截器对象
- 扫描这和包下的所有类org.myspringmvc.web.servlet.mvc.method.annotation,全部实例化,纳入IoC容器管理
Spring容器:ApplicationContext
SpringWeb容器:WebApplicationContext
组件扫描
springmvc.xml文件
java
<?xml version="1.0" encoding="utf-8" ?>
<beans>
<!--
拦截器
视图解析器
组件扫描
-->
<component-scan base-package="org.springmvc.oa.controller"/>
<!-- 视图解析器-->
<bean class="org.springmvc.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀-->
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<!-- 后缀-->
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<!-- 拦截器-->
<interceptors>
<bean class="org.springmvc.oa.interceptors.Interceptor1"></bean>
<bean class="org.springmvc.oa.interceptors.Interceptor2"></bean>
</interceptors>
</beans>
添加解析XML文件的依赖
XML
<!--dom4j-->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!--jaxen-->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
ApplicationContext
java
public class ApplicationContext {
private Map<String, Object> beanMap = new HashMap<>();
public ApplicationContext(String xmlPath) throws Exception {
// 组件扫描
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(new File(xmlPath));
Element componentScanElement = (Element)document.selectSingleNode("/beans/context:component-scan");
String basePackage = componentScanElement.attributeValue("base-package");
System.out.println("组件扫描:" + basePackage);
componentScan(basePackage);
System.out.println("Spring Web容器当下状态:" + beanMap);
}
private void componentScan(String basePackage) throws Exception{
String dirPath = Thread.currentThread().getContextClassLoader().getResource(basePackage.replace(".", "/")).getPath();
File file = new File(URLDecoder.decode(dirPath));
if(file.isDirectory()){
File[] files = file.listFiles();
for (File classFile : files){
if(classFile.getName().endsWith(".class")){
String className = basePackage + "." + classFile.getName().substring(0, classFile.getName().lastIndexOf("."));
Class<?> clazz = Class.forName(className);
Constructor<?> defaultCon = clazz.getDeclaredConstructor();
Object bean = defaultCon.newInstance();
beanMap.put(firstCharLowerCase(clazz.getSimpleName()), bean);
}
}
}
}
private String firstCharLowerCase(String simpleName) {
return simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
}
public Object getBean(String beanName){
return beanMap.get(beanName);
}
}
组件扫描的beanMap结果
WebApplicationContext
java
package org.springmvc.web.context;
import jakarta.servlet.ServletContext;
import org.dom4j.DocumentException;
import org.springmvc.context.ApplicationContext;
import java.lang.reflect.InvocationTargetException;
public class WebApplicationContext extends ApplicationContext {
private ServletContext servletContext;
private String springMvcConfigPath;
public WebApplicationContext() {
}
public WebApplicationContext(ServletContext servletContext, String springMvcConfigPath) throws DocumentException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
super(springMvcConfigPath);
this.servletContext = servletContext;
this.springMvcConfigPath = springMvcConfigPath;
}
/**
* 获取
* @return servletContext
*/
public ServletContext getServletContext() {
return servletContext;
}
/**
* 设置
* @param servletContext
*/
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
/**
* 获取
* @return springMvcConfigPath
*/
public String getSpringMvcConfigPath() {
return springMvcConfigPath;
}
/**
* 设置
* @param springMvcConfigPath
*/
public void setSpringMvcConfigPath(String springMvcConfigPath) {
this.springMvcConfigPath = springMvcConfigPath;
}
public String toString() {
return "WebApplicationContext{servletContext = " + servletContext + ", springMvcConfigPath = " + springMvcConfigPath + "}";
}
}
创建视图解析器对象
InternalResourceViewResolver
内部资源视图解析器
java
package org.springmvc.web.servlet.view;
import org.springmvc.web.servlet.View;
import org.springmvc.web.servlet.ViewResolver;
import java.util.Locale;
/*
内部资源解析器
*/
public class InternalResourceViewResolver implements ViewResolver {
String prefix;
String suffix;
public InternalResourceViewResolver() {
}
public InternalResourceViewResolver(String prefix, String suffix) {
this.prefix = prefix;
this.suffix = suffix;
}
/*
将逻辑试图名字 转换为物理视图名称 并以View对象返回
*/
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return new InternalResourceView("text/html;charset-UTF-8", prefix+viewName+suffix);
}
/**
* 获取
* @return prefix
*/
public String getPrefix() {
return prefix;
}
/**
* 设置
* @param prefix
*/
public void setPrefix(String prefix) {
this.prefix = prefix;
}
/**
* 获取
* @return suffix
*/
public String getSuffix() {
return suffix;
}
/**
* 设置
* @param suffix
*/
public void setSuffix(String suffix) {
this.suffix = suffix;
}
public String toString() {
return "InternalResourceViewResolver{prefix = " + prefix + ", suffix = " + suffix + "}";
}
/**
* 获取
* @return suffix
*/
/**
* 获取
* @return prefix
*/
}
创建视图解析器对象
java
private void createViewResolver(Element viewResolverElement) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String viewResolverClassName=viewResolverElement.attributeValue("class");
System.out.println("视图解析器类名"+viewResolverClassName);
Class clazz= Class.forName(viewResolverClassName);
Object bean = clazz.newInstance();
//bean节点下子节点property
List<Element> propertyElements=viewResolverElement.elements(Constant.PROPERTY_TAG_NAME);
for(Element propertyElement:propertyElements){
//获取属性名
String fieldName=propertyElement.attributeValue(Constant.PROPERTY_NAME);
String value=propertyElement.element(Constant.PROPERTY_VALUE).getTextTrim();
//将属性名转为set方法
String setMethodName=fieldNameToSetMethod(fieldName);
//通过反射机制调用set方法
Method setMethod = clazz.getDeclaredMethod(setMethodName,String.class);
setMethod.invoke(bean,value);
}
beanMap.put(Constant.VIEW_RESOLVER, bean);
}

创建拦截器对象
java
private void createInteceptor(Element interceptorElement) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
List<Element> interceptorElements=interceptorElement.elements("bean");
List<HandlerInterceptor> interceptors=new ArrayList<>();
for(Element interceptor:interceptorElements){
Class<?> clazz=Class.forName(interceptor.attributeValue("class"));
Object bean=clazz.newInstance();
interceptors.add((HandlerInterceptor)bean);
}
beanMap.put(Constant.INTERCEPROTS,interceptors);
}

2.初始化HandlerMapping和初始化HandlerAdapter
初始化annotation包下所有类的实例
java
private void createHandlerMapping(String defaultPackage,Map<RequestMappingInfo, HandlerMethod>map) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//System.out.println(defaultPackage);
// 将这个包下所有的类实例化:org.myspringmvc.web.servlet.mvc.method.annotation
//获取绝对路径
String dirPath=Thread.currentThread().getContextClassLoader().getResource(defaultPackage.replace('.', '/')).getPath();
File file=new File(URLDecoder.decode(dirPath));
//获取里面所有的子文件
if(file.isDirectory()){
File[] files = file.listFiles();
for(File classFile : files){
if(classFile.getName().endsWith(Constant.SUFFER_CLASS)){
//全类名
String className=defaultPackage+"."+classFile.getName().substring(0,classFile.getName().lastIndexOf("."));
Class<?>clazz=Class.forName(className);
if(HandlerMapping.class.isAssignableFrom(clazz)){
Constructor<?>defaultCon= clazz.getDeclaredConstructor(Map.class);
Object bean=defaultCon.newInstance(map);
beanMap.put(Constant.HANDLER_MAPPING, bean);
}
if(HandlerAdapter.class.isAssignableFrom(clazz)){
Constructor<?>defaultCon= clazz.getDeclaredConstructor();
Object bean=defaultCon.newInstance();
beanMap.put(Constant.HANDLER_ADAPTER, bean);
}
}
}
}
}

2.初始化Servlet对象
DispatchServlet init()
java
public void init(){
//找到springmvc.xml文件
/*
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
*/
//根据以上配置springmvc.xml文件
//获取SpringConfig对象(Servlet配置信息对象 该对象由web容器自动创建 并且将其传递给init方法
// )
ServletConfig servletConfig = this.getServletConfig();
String contextConfigLocation = servletConfig.getInitParameter(Constant.CONTEXT_CONFIG_LOCATION);
String springMvcXmlPath=getSpringMvcXmlPath(contextConfigLocation);
System.out.println("Spring MVC配置文件路径解析完成:" + springMvcXmlPath);
//初始化Spring Web容器
WebApplicationContext webApplicationContext = null;
try {
webApplicationContext = new WebApplicationContext(this.getServletContext(), springMvcXmlPath);
} catch (DocumentException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
this.getServletContext().setAttribute(Constant.WEB_APPLICATION_CONTEXT, webApplicationContext);
//初始化HandlerMapping
this.handlerMapping=(HandlerMapping)webApplicationContext.getBean(Constant.HANDLER_MAPPING);
//初始化HandlerAdapter
this.handlerAdapter=(HandlerAdapter)webApplicationContext.getBean(Constant.HANDLER_ADAPTER);
//初始化试图解析器
this.viewResolver=(ViewResolver)webApplicationContext.getBean(Constant.VIEW_RESOLVER);
}
private String getSpringMvcXmlPath(String contextConfigLocation) {
if(contextConfigLocation.startsWith(Constant.CLASSPATH)){
String path=contextConfigLocation.substring(Constant.CLASSPATH.length()).trim();
//类路径中找
String springMvcXmlPath=Thread.currentThread().getContextClassLoader().getResource(path).getPath();
// 对路径解码,防止路径中有 % 等字符。
return URLDecoder.decode(springMvcXmlPath, Charset.defaultCharset());
}
return null;
}
doDispath方法
java
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
doDispatch(req, resp);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 处理请求的核心方法
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//访问浏览器才能断点到这
//请求对象获取对应的处理器执行连对象
HandlerExecutionChain mappedHandler=handlerMapping.getHandler(request);
//获取处理器适配器对象
HandlerAdapter adapter = this.handlerAdapter;
//3.执行拦截器中的preHandle方法
if(!mappedHandler.applyPreHandle(request,response)){
return;//false的话
}
//4.执行处理器方法 返回ModelAndView
ModelAndView mv=adapter.handle(request,response,mappedHandler.getHandler());
System.out.println("处理器执行连对象:"+mappedHandler);
//5.执行拦截器中postHanlder
mappedHandler.applyPostHandle(request,response,mv);
//6.试图解析器 逻辑试图名称转为物理视图名称
View view=viewResolver.resolveViewName(mv.getView().toString(),request.getLocale());
view.render(mv.getModel(),request,response);
//执行拦截器渲染之后的afterCompletetion方法
mappedHandler.triggerAfterCompletion(request,response,null);
}
根据请求获取处理器执行链
HandlerExecutionChain mappedHandler=handlerMapping.getHandler(request);
HandlerMapping
java
public interface HandlerMapping {
/**
* ClassName: HandlerMapping
* Description: 主要是通过请求获取对应的处理器执行链。
* Datetime: 2024/4/2 8:50
* Author: 老杜@动力节点
* Version: 1.0
*/
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
HandlerMethod
java
package org.springmvc.web.method;
import java.lang.reflect.Method;
/*
处理器方法 controller
*/
public class HandlerMethod {
/*
处理器对象
*/
private Object handler;
/**
* 要执行的方法
*/
private Method method;
public HandlerMethod() {
}
public HandlerMethod(Object handler, Method method) {
this.handler = handler;
this.method = method;
}
/**
* 获取
* @return handler
*/
public Object getHandler() {
return handler;
}
/**
* 设置
* @param handler
*/
public void setHandler(Object handler) {
this.handler = handler;
}
/**
* 获取
* @return method
*/
public Method getMethod() {
return method;
}
/**
* 设置
* @param method
*/
public void setMethod(Method method) {
this.method = method;
}
public String toString() {
return "HandlerMethod{handler = " + handler + ", method = " + method + "}";
}
}
RequestMappingInfo
java
package org.springmvc.web.servlet;
import java.util.Objects;
public class RequestMappingInfo {
private String requestURI;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RequestMappingInfo that = (RequestMappingInfo) o;
return Objects.equals(requestURI, that.requestURI) && Objects.equals(method, that.method);
}
@Override
public int hashCode() {
return Objects.hash(requestURI, method);
}
//GET POST PUT DELETE
private String method;
public RequestMappingInfo() {
}
public RequestMappingInfo(String requestURI, String method) {
this.requestURI = requestURI;
this.method = method;
}
/**
* 获取
* @return requestURI
*/
public String getRequestURI() {
return requestURI;
}
/**
* 设置
* @param requestURI
*/
public void setRequestURI(String requestURI) {
this.requestURI = requestURI;
}
/**
* 获取
* @return method
*/
public String getMethod() {
return method;
}
/**
* 设置
* @param method
*/
public void setMethod(String method) {
this.method = method;
}
public String toString() {
return "RequestMappingInfo{requestURI = " + requestURI + ", method = " + method + "}";
}
}
RequestMappingHandlerMapping
java
package org.springmvc.web.servlet.mvc.method.annotation;
import jakarta.servlet.http.HttpServletRequest;
import org.springmvc.web.constant.Constant;
import org.springmvc.web.context.WebApplicationContext;
import org.springmvc.web.method.HandlerMethod;
import org.springmvc.web.servlet.*;
import java.util.List;
import java.util.Map;
/*
处理器映射器 专门为 @RequestMapping 注解的类服务的处理器映射器
通过前端提交的请求 来底层映射要执行的HandlerMethod
*/
public class RequestMappingHandlerMapping implements HandlerMapping {
private Map<RequestMappingInfo, HandlerMethod> map;
/*
创建HandlerMapping对象时 给map赋值
*/
public RequestMappingHandlerMapping(Map<RequestMappingInfo, HandlerMethod> map) {
this.map = map;
}
@Override
public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//通过request对象 获取请求路径,请求方式 封装程RequestMappingInfo
RequestMappingInfo requestMappingInfo=new RequestMappingInfo(request.getServletPath(),request.getMethod());
//******************必须重写 如果补充写 key是对象 对于相同请求创建多个对象 可能认为是不同的
HandlerExecutionChain handlerExecutionChain =new HandlerExecutionChain();
//给执行连设置handlerMethod
handlerExecutionChain.setHandler(map.get(requestMappingInfo));
//给执行连设置拦截器
//通过Spring容器
WebApplicationContext webApplicationContext=(WebApplicationContext)request.getServletContext().getAttribute(Constant.WEB_APPLICATION_CONTEXT);
List<HandlerInterceptor> interceptors=(List<HandlerInterceptor>)webApplicationContext.getBean(Constant.INTERCEPROTS);
handlerExecutionChain.setInterceptors(interceptors);
return handlerExecutionChain;
}
}
处理器执行链对象

注意:
public RequestMappingHandlerMapping(Map<RequestMappingInfo, HandlerMethod> map) {
this.map = map;
}
包扫描的时候初始化RequestMappingHandlerMapping时 要传入Map对象 所以包扫描要改为下面的代码
java
private Map<RequestMappingInfo, HandlerMethod> componentScan(String basePackage) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Map<RequestMappingInfo, HandlerMethod>handlerMethodMap=new HashMap<>();
//获取绝对路径
String dirPath=Thread.currentThread().getContextClassLoader().getResource(basePackage
.replace(".","/")).getPath();
File file=new File(URLDecoder.decode(dirPath));//封装为文件
//获取里面所有的子文件
if(file.isDirectory()){
File[] files = file.listFiles();
for(File classFile:files){
if(classFile.getName().endsWith(Constant.SUFFER_CLASS)){
String className=basePackage+"."+classFile.getName().substring(0,classFile.getName().lastIndexOf("."));
Class<?> clazz = Class.forName(className);
Constructor<?>defaultCon= clazz.getDeclaredConstructor();
//System.out.println("简单类名"+clazz.getSimpleName());
Object bean=defaultCon.newInstance();
beanMap.put(firstCharLowerCase(clazz.getSimpleName()), bean);
//UserController 默认beanName 首字母小写
//获取类上面的注解 @Controller注解包围
if(clazz.isAnnotationPresent(Controller.class)){//被Controller注解包裹
//获取类中所有的方法
Method []methods=clazz.getDeclaredMethods();
for(Method method:methods){
//如果该注解被RequestMapping注解包裹
if(method.isAnnotationPresent(RequestMapping.class)){
RequestMapping requestMapping=method.getAnnotation(RequestMapping.class);
String requestURI=requestMapping.value()[0];
String requestMethod=requestMapping.method().toString();// GET
RequestMappingInfo requestMappingInfo=new RequestMappingInfo(requestURI,requestMethod);
HandlerMethod handlerMethod=new HandlerMethod();//请求的方法
handlerMethod.setHandler(bean);
handlerMethod.setMethod(method);
handlerMethodMap.put(requestMappingInfo,handlerMethod);
}
}
}
}
}
}
执行拦截器的中preHandler方法
java
public boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i <interceptors.size() ; i++) {
HandlerInterceptor handlerInterceptor = interceptors.get(i);
boolean result=handlerInterceptor.preHandle(request,response,handler);
if(!result){
//执行拦截器的AfterCompletion
triggerAfterCompletion(request,response,handler);
return false;
}
}
return true;
}
.执行处理器方法 返回ModelAndView
java
public interface HandlerAdapter {
ModelAndView handle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception;
}
public class RequestMappingHandlerAdapter implements HandlerAdapter {
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//需要调用处理器方法
HandlerMethod handlerMethod = (HandlerMethod)handler;
//获取控制器
Object controller=handlerMethod.getHandler();
//获取调用的方法
Method method=handlerMethod.getMethod();
ModelMap modelMap=new ModelMap();
//通过反射机制调用
String viewName=(String)method.invoke(controller,modelMap);
//自己写的目前需要 Controller指定ModelMap
//还有一个特殊要求 要求返回逻辑试图名称
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName(viewName);
modelAndView.setModel(modelMap);
return modelAndView;
}
}
package org.springmvc.ui;
import java.util.LinkedHashMap;
public class ModelMap extends LinkedHashMap<String, Object> {
public ModelMap() {
}
public ModelMap addAttribute(String name, String value) {
this.put(name,value);
return this;
}
}
package org.springmvc.oa.controller;
import org.springmvc.stereotype.Controller;
import org.springmvc.ui.ModelMap;
import org.springmvc.web.bind.annotation.RequestMapping;
import org.springmvc.web.bind.annotation.RequestMethod;
@Controller
public class UserController {
@RequestMapping(value ="/index", method = RequestMethod.GET)
public String index(ModelMap modelMap){
modelMap.put("name","liwu");
return "index";
}
}
执行拦截器中postHanlder
java
public void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
for(int i=interceptors.size()-1;i>=0;i--){
HandlerInterceptor handlerInterceptor = interceptors.get(i);
handlerInterceptor.postHandle(request,response,handler,mv);
}
}
视图解析器 逻辑试图名称转为物理视图名称
java
public interface ViewResolver {
/*
解析逻辑视图名称,返回视图对象
*/
View resolveViewName(String viewName, Locale locale) throws Exception;
}
public View resolveViewName(String viewName, Locale locale) throws Exception {
return new InternalResourceView("text/html;charset-UTF-8", prefix+viewName+suffix);
}
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
//设置响应类型
response.setContentType(contentType);
//将model数据存储到request域中
//默认情况下跳转到视图以转发方式
model.forEach((key,value)->{
request.setAttribute(key,value);
});
request.getRequestDispatcher(path).forward(request,response);
}
执行拦截器渲染之后的afterCompletetion方法
java
public void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
for(int i=interceptors.size()-1;i>=0;i--){
HandlerInterceptor handlerInterceptor = interceptors.get(i);
handlerInterceptor.afterCompletion(request, response,handler, (Exception) o);
}
}
SSM整合
引入相关依赖
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>
<groupId>org.springmvc</groupId>
<artifactId>ssm-annotation</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!--springmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.1.4</version>
</dependency>
<!--spring jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.1.4</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.15</version>
</dependency>
<!--mybatis spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.3.0</version>
</dependency>
<!--德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.22</version>
</dependency>
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version>
</dependency>
<!--servlet api-->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
<!--logback-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.3</version>
</dependency>
<!--thymeleaf和spring6的整合依赖-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring6</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
创建包结构

创建webapp目录

Spring整合Mybatis
编写mybatis.properties
java
mybatis.driverClassName=com.mysql.cj.jdbc.Driver
mybatis.url=jdbc:mysql://localhost:3306/db03?useSSL=false&allowPublicKeyRetrieval=true
mybatis.username=root
mybatis.password=123456
mybatis.mapperLocations=classpath*:com/gao/ssm/dao/*Mapper.xml
MybatisProperties
java
package com.gao.ssm.dao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@PropertySource("classpath:mybatis.properties")
public class MybatisProperties {
@Value("${mybatis.driverClassName}")
private String driverClassName;
@Value("${mybatis.url}")
private String url;
@Value("${mybatis.username}")
private String username;
@Value("${mybatis.password}")
private String password;
@Value("${mybatis.mapperLocations}")
private String mapperLocations;
public MybatisProperties() {
}
public MybatisProperties(String driverClassName, String url, String username, String password, String mapperLocations) {
this.driverClassName = driverClassName;
this.url = url;
this.username = username;
this.password = password;
this.mapperLocations = mapperLocations;
}
/**
* 获取
* @return driverClassName
*/
public String getDriverClassName() {
return driverClassName;
}
/**
* 设置
* @param driverClassName
*/
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
/**
* 获取
* @return url
*/
public String getUrl() {
return url;
}
/**
* 设置
* @param url
*/
public void setUrl(String url) {
this.url = url;
}
/**
* 获取
* @return username
*/
public String getUsername() {
return username;
}
/**
* 设置
* @param username
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 获取
* @return password
*/
public String getPassword() {
return password;
}
/**
* 设置
* @param password
*/
public void setPassword(String password) {
this.password = password;
}
/**
* 获取
* @return mapperLocations
*/
public String getMapperLocations() {
return mapperLocations;
}
/**
* 设置
* @param mapperLocations
*/
public void setMapperLocations(String mapperLocations) {
this.mapperLocations = mapperLocations;
}
public String toString() {
return "MybatisProperties{driverClassName = " + driverClassName + ", url = " + url + ", username = " + username + ", password = " + password + ", mapperLocations = " + mapperLocations + "}";
}
}
MybatisConfig
java
package com.gao.ssm.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.gao.ssm.dao.MybatisProperties;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.io.IOException;
@Configuration
@ComponentScan("com.gao.ssm.dao")
@MapperScan("com.gao.ssm.dao")
public class MybatisConfig {
@Autowired
private MybatisProperties mybatisProperties;
@Bean
public DataSource dataSource(){
DruidDataSource dataSource=new DruidDataSource();
dataSource.setUsername(mybatisProperties.getUsername());
dataSource.setPassword(mybatisProperties.getPassword());
dataSource.setUrl(mybatisProperties.getUrl());
dataSource.setDriverClassName(mybatisProperties.getDriverClassName());
return dataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) throws IOException {
SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
ResourcePatternResolver resolver=new PathMatchingResourcePatternResolver();
Resource[]resources=resolver.getResources(mybatisProperties.getMapperLocations());
sqlSessionFactoryBean.setMapperLocations(resources);
return sqlSessionFactoryBean;
}
@Bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
SpringConfig
java
package com.gao.ssm.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@ComponentScan("com.gao.ssm.service")
@EnableTransactionManagement
@Import({MybatisConfig.class})
public class SpringConfig {
}
Spring整合Spring MVC
java
package com.gao.ssm.config;
import jakarta.servlet.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
@Configuration
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
/*
配置Spring的配置文件
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
/*
SpringMVC配置文件
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
/*
配置DispatcherServlet的映射规则,即url-pattern
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
/**
* Spring的配置
* @return
*/
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceRequestEncoding(true);
characterEncodingFilter.setForceResponseEncoding(true);
//!--隐藏的HTTP请求方式过滤器 字符编码过滤器之后-->
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};
}
}
SpringMvcConfig
java
package com.gao.ssm.config;
import com.gao.ssm.interceptor.MyInterceptor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring6.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ITemplateResolver;
import java.util.List;
import java.util.Properties;
@Configuration
@ComponentScan("com.gao.ssm.handler")
@Import({SpringConfig.class})
@EnableWebMvc
//开启注解驱动
public class SpringMvcConfig implements WebMvcConfigurer {
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
SimpleMappingExceptionResolver simpleHandlerExceptionResolver=new SimpleMappingExceptionResolver();
Properties prop = new Properties();
prop.setProperty("java.lang.Exception", "tip");
simpleHandlerExceptionResolver.setExceptionMappings(prop);
simpleHandlerExceptionResolver.setExceptionAttribute("e");
resolvers.add(simpleHandlerExceptionResolver);
}
@Bean
public ThymeleafViewResolver getViewResolver(SpringTemplateEngine springTemplateEngine) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(springTemplateEngine);
resolver.setCharacterEncoding("UTF-8");
resolver.setOrder(1);
return resolver;
}
@Bean
public SpringTemplateEngine templateEngine(ITemplateResolver iTemplateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(iTemplateResolver);
return templateEngine;
}
public void addInterceptors(InterceptorRegistry registry) {
MyInterceptor myInterceptor = new MyInterceptor();
registry.addInterceptor(myInterceptor).addPathPatterns("/**").excludePathPatterns("/test");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index").setViewName("index");
}
@Bean
public ITemplateResolver templateResolver(ApplicationContext applicationContext) {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/WEB-INF/thymeleaf/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("UTF-8");
resolver.setCacheable(false);//开发时关闭缓存,改动即可生效
return resolver;
}
@Override
//开启静态资源处理
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
添加事务控制
java
@Configuration
@ComponentScan("com.gao.ssm.service")
@EnableTransactionManagement
@Import({MybatisConfig.class})
public class SpringConfig {
}
@Transactional()
@Service
public class EmpServiceImpl implements EmpService{
pojo类编写
java
package com.gao.ssm.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 员工实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
private Integer id; //ID
private String username; //用户名
private String password; //密码
private String name; //姓名
private Short gender; //性别 , 1 男, 2 女
private String image; //图像url
private Short job; //职位 , 1 班主任 , 2 讲师 , 3 学工主管 , 4 教研主管 , 5 咨询师
private LocalDate entrydate; //入职日期
private Integer deptId; //部门ID
private LocalDateTime createTime; //创建时间
private LocalDateTime updateTime; //修改时间
}
dao编写
java
package com.gao.ssm.dao;
import com.gao.ssm.bean.Emp;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
public interface EmpDao {
List<Emp> listAll();
Emp listOne(Emp emp);
void add(Emp emp);
}
service编写
java
package com.gao.ssm.service;
import com.gao.ssm.bean.Emp;
import java.util.List;
public interface EmpService{
public void register(Emp emp);
public List<Emp> listAll();
}
package com.gao.ssm.service;
import com.gao.ssm.bean.Emp;
import com.gao.ssm.dao.EmpDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Transactional()
@Service
public class EmpServiceImpl implements EmpService{
@Autowired
private EmpDao empDao;
@Override
public void register(Emp emp) {
empDao.add(emp);
}
@Override
public List<Emp> listAll() {
return empDao.listAll();
}
}
handler编写
java
package com.gao.ssm.handler;
import com.gao.ssm.bean.Emp;
import com.gao.ssm.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/emp")
public class EmpController {
@Autowired
private EmpService empService;
@RequestMapping("/list")
public String list(){
return empService.listAll().toString();
}
}
EmpMapper.xml
java
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//MyBatis//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gao.ssm.dao.EmpDao">
<!-- 查询所有员工 -->
<select id="listAll" resultType="com.gao.ssm.bean.Emp">
SELECT * FROM emp
</select>
<!-- 根据 ID 查询单个员工 -->
<select id="listOne" resultType="com.gao.ssm.bean.Emp" parameterType="java.lang.Integer">
SELECT * FROM emp WHERE id = #{id}
</select>
<!-- 添加员工,返回主键 ID -->
<insert id="add" parameterType="com.gao.ssm.bean.Emp" useGeneratedKeys="true" keyProperty="id">
INSERT INTO emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)
VALUES (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})
</insert>
</mapper>
测试
html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ssm整合</title>
<!--引入vue-->
<script th:src="@{/static/js/vue3.4.21.js}"></script>
<!--引入axios-->
<script th:src="@{/static/js/axios.min.js}"></script>
</head>
<body>
<div id="app">
<button @click="getMessage">查询所有用户</button>
<h1>{{message}}</h1>
</div>
<script th:inline="javascript">
Vue.createApp({
data(){
return {
message : '很多信息'
}
},
methods : {
async getMessage(){
console.log("------------查询")
let response = await axios.get("/ssm/emp/list")
console.log(response)
this.message = response.data
}
}
}).mount("#app")
</script>
</body>
</html>