云计算百科
云计算领域专业知识百科平台

手写SpringMVC(基本框架)

服务器启动阶段处理

分析服务器启动阶段都都需要初始化什么?

1.初始化Spring容器

  • 组件扫描包下的类纳入IOC容器管理
  • 创建视图解析器对象
  • 创建所有的拦截器对象
  • 扫描这和包下的所有类org.myspringmvc.web.servlet.mvc.method.annotation,全部实例化,纳入IoC容器管理
  • Spring容器:ApplicationContext

    SpringWeb容器:WebApplicationContext

    组件扫描
    springmvc.xml文件

    <?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文件的依赖

    <!–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

    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

    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

    内部资源视图解析器

    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
    */

    }

     创建视图解析器对象

    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);
    }

     

    创建拦截器对象

    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包下所有类的实例

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

    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方法

    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

    public interface HandlerMapping {
    /**
    * ClassName: HandlerMapping
    * Description: 主要是通过请求获取对应的处理器执行链。
    * Datetime: 2024/4/2 8:50
    * Author: 老杜@动力节点
    * Version: 1.0
    */
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
    }

     HandlerMethod

    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

    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

    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对象 所以包扫描要改为下面的代码

    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方法

    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

    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

    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);
    }
    }

    视图解析器 逻辑试图名称转为物理视图名称

    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方法

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

    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 

    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

    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

    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

    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

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

    添加事务控制

    @Configuration
    @ComponentScan("com.gao.ssm.service")
    @EnableTransactionManagement
    @Import({MybatisConfig.class})
    public class SpringConfig {
    }

    @Transactional()
    @Service
    public class EmpServiceImpl implements EmpService{

    pojo类编写

    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编写 

    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编写

    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编写

    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

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

    测试 

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

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 手写SpringMVC(基本框架)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!