欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【java高级进阶笔记3】之springMVC

程序员文章站 2022-07-06 15:19:38
MVC框架设计实现及SpringMVC源码分析SpringMVC应用1、Spring MVC 简介SpringMVC高级技术手写SpringMVC框架SpringMVC框架深度剖析SSM整合二级目录三级目录SpringMVC应用1、Spring MVC 简介我们的开发架构⼀般都是基于两种形式:C/S 架构,也就是客户端/服务器B/S 架构,也就是浏览器服务器开发使用比较多的是三层架构,每一层各司其职,如下图:三层架构职责表 现 层表现层也就是我们常说的web层。它负责接收...

1、SpringMVC应用

1.1 C/S架构和B/S架构

C/S 架构,也就是客户端/服务器
B/S 架构,也就是浏览器服务器

1.2 三层架构

三层架构 职责
表 现 层 表现层也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用 http协议请求web层web需要接收http请求,完成http响应。MVC是表现层的设计模型,和其他层没有关系
业 务 层 就是我们常说的service层。它负责业务逻辑处理,和我们开发项目的需求息息相关。web层依赖业务层,但是业务层不依赖web层
持 久 层 也就是我们是常说的dao层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体

1.3 MVC设计模式

MVC分层 说明
Model(模型) 模型包含业务模型和数据模型,数据模型用户封装数据,业务模型用户处理业务。
View(视图) 通常指的就是我们的jsp或者html。作用一般就是展示数据的。通常视图是依据模型数据创建的。
Controller(控制器) 是应用程序中处理用户交互的部分。作用一般般就是处理程序逻辑的

注:MVC提倡每一层只编写自己的东西,不编写任何其他的代码;分层是为了解耦,解耦是为了维护方便和分工协作。

1.4 SpringMVC是什么?

定义:SpringMVC全名叫Spring Web MVC,是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品

架构图如下:
【java高级进阶笔记3】之springMVC

1.5 SpringMVC的开发流程

1)配置DispatcherServlet前端控制器

<servlet>
  <servlet-name>springmvc</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:springmvc.xml</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>springmvc</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

说明:url-pattern配置有三种方式:
方式一:带后缀,比如*.action,该方式比较精确
方式二:/ 不会拦截.jsp,但是会拦截html等静态资源
方式三:/* 拦截所有,包括.jsp

2)开发处理具体业务逻辑的Handler(@Controller、@RequestMapping)

@RequestMapping("/handle01")
public ModelAndView handle01() {
    Date date = new Date();// 服务器当前时间
    // 返回服务器时间到前段页面
    ModelAndView modelAndView = new ModelAndView();// 封装了数据和页面的信息
    // addObject 其实是向请求域中request.setAttribute("date",date);
    modelAndView.addObject("date",date);
    // 视图信息(封装跳转的页面信息)
    modelAndView.setViewName("success");
    return modelAndView;
}

3)xml配置文件配置controller扫描,配置springmvc三大件

<!--开启controller扫描-->
<context:component-scan base-package="com.lagou.edu.controller"/>
<!-- 配置springmvc的视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>
<!-- 自动注册最合适的处理器映射器 处理器适配器 -->
<mvc:annotation-driven/>

4)将xml文件路径告诉springmvc(DispatcherServlet)

<init-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:springmvc.xml</param-value>
</init-param>

1.6 SpringMVC请求处理流程

如下图所示:
【java高级进阶笔记3】之springMVC

1.7 SpringMVC请求处理步骤

第⼀步:⽤户发送请求⾄前端控制器DispatcherServlet
第⼆步:DispatcherServlet收到请求调⽤HandlerMapping处理器映射器
第三步:处理器映射器根据请求Url找到具体的Handler(后端控制器),⽣成处理器对象及处理器拦截
器(如果 有则⽣成)⼀并返回DispatcherServlet
第四步:DispatcherServlet调⽤HandlerAdapter处理器适配器去调⽤Handler
第五步:处理器适配器执⾏Handler
第六步:Handler执⾏完成给处理器适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回 ModelAndView,ModelAndView 是SpringMVC 框架的⼀个
底层对 象,包括 Model 和 View
第⼋步:前端控制器请求视图解析器去进⾏视图解析,根据逻辑视图名来解析真正的视图。
第九步:视图解析器向前端控制器返回View
第⼗步:前端控制器进⾏视图渲染,就是将模型数据(在 ModelAndView 对象中)填充到 request 域
第⼗⼀步:前端控制器向⽤户响应结果

1.8、Spring MVC 九⼤组件

组件 说明
HandlerMapping(处理器映射器) HandlerMapping是用来查找Handler的(处理器),在请求到达后,HandlerMapping的作用便是找到请求相应的处理器
HandlerAdapter(处理器适配器) HandlerAdapter的职责要让固定的Servlet处理方法调用Handler来进行处理
HandlerExceptionResolver HandlerExceptionResolver用于处理Handler产生的异常情况。它的作用是根据异常设置ModelAndView,之后交给渲染方法进行渲染,渲染方法会将ModelAndView渲染成页面
ViewResolver ViewResolver即视图解析器,用于将String类型的视图名和Locale解析为View类型的视图,只有一个resolveViewName()方法,Controller层返回的String类型视图名viewName最终会在这里被解析成为View
RequestToViewNameTranslator RequestToViewNameTranslator组件的作用是从请求中获取ViewName.因为ViewResolver根据ViewName查找View,但有的Handler处理完成后没有设置View和ViewName,便要通过这个组件从请求中查找ViewName
ThemeResolver ThemeResolver组件是?来解析主题的
MultipartResolver MultipartResolver用于上传请求,通过将普通的请求包装成MultipartHttpServletRequest来实现。MultipartHttpServletRequest可以通过getFile()方法直接获得文件
LocaleResolver LocaleResolver用于从请求中解析出Locale,比如中国Locale是zh-CN,用来表示一个区域。这个组件也是i18n的基础
FlashMapManager FlashMap用于重定向时的参数传递,比如在处理用户订单时候,为了避免重复提交,可以处理完post请求之后重定向到一个get请求,这个get请求可以用来显示订单详情之类的信息

1.9 数据输出机制之Model、Map、ModelMap

方式一:直接声明形参ModelMap,封装数据

@RequestMapping("/handle02")
public String handle02(ModelMap modelMap) {
    Date date = new Date();// 服务器当前时间
    modelMap.addAttribute("date",date);
    return "success";
}

方式二:直接声明形参Model,封装数据

@RequestMapping("/handle03")
public String handle03(Model model) {
    Date date = new Date();// 服务器当前时间
    model.addAttribute("date",date);
    return "success";
}

方式三:直接声明形参Map集合,封装数据

@RequestMapping("/handle04")
public String handle04(Map<String, Object> map) {
    Date date = new Date();// 服务器当前时间
    map.put("date", date);
    return "success";
}

说明:这三种类型,运行时都是BindingAwareModelMap,BindingAwareModelMap继承了ExtendedModelMap,ExtendedModelMap继承了ModelMap,实现了Model接口

1.10 springMVC请求参数绑定

方式一:使用servlet原生对象
请求url:http://localhost:8080/test/handle02?id=1

@RequestMapping("/handle02")
public ModelAndView handle02(HttpServletRequest request, HttpServletResponse response,HttpSession session) {
    String id = request.getParameter("id");
    Date date = new Date();
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("date",date);
    modelAndView.setViewName("success");
    return modelAndView;
}

方式二:接收简单数据类型参数
请求url:http://localhost:8080/test/handle03?id=1&name=zhangsan

@RequestMapping("/handle03")
public ModelAndView handle03(String name, Integer id) {
    Date date = new Date();
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("id",id);
    modelAndView.addObject("name",name);
    modelAndView.setViewName("success");
    return modelAndView;
}

方式三:接收pojo类型参数
请求url:http://localhost:8080/test/handle04?id=1&name=zhangsan

@RequestMapping("/handle04")
public ModelAndView handle04(User user) {
    Date date = new Date();
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("id",user.getId());
    modelAndView.addObject("name",user.getName());
    modelAndView.setViewName("success");
    return modelAndView;
}
public class User {
    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

1.11 对 Restful风格请求支持

什么是REST
REST(英文:Representational State Transfer,简称 REST)Restful是一种web软件架构风格,它不是标准也不是协议,它倡导的是一个资源定位及资源操作的风格。互联⽹中的所有东⻄都是资源,既然是资源就会有⼀个唯⼀的uri标识它

案例
get 查询,获取资源
post 增加,新建资源
put 更新
delete 删除资源

前端代码

<div>
    <h2>SpringMVC对Restful风格url的支持</h2>
    <fieldset>
        <p>测试用例:SpringMVC对Restful风格url的支持</p>
        <!-- get请求 -->
        <a href="/demo/handle/15">rest_get测试</a>

        <!-- post请求 -->
        <form method="post" action="/demo/handle">
            <input type="text" name="username"/>
            <input type="submit" value="提交rest_post请求"/>
        </form>

        <!-- put请求(声明的是post请求) -->
        <form method="post" action="/demo/handle/15/lisi">
            <input type="hidden" name="_method" value="put"/>
            <input type="submit" value="提交rest_put请求"/>
        </form>
        
        <!-- delete请求(声明的是post请求) -->
        <form method="post" action="/demo/handle/15">
            <input type="hidden" name="_method" value="delete"/>
            <input type="submit" value="提交rest_delete请求"/>
        </form>
    </fieldset>
</div>

后台控制器代码,通过@PathVariable 获取url中的参数

/*
 * get请求   /test/handle/15
 */
@RequestMapping(value = "/handle/{id}",method = {RequestMethod.GET})
public ModelAndView handleGet(@PathVariable("id") Integer id) {
    Date date = new Date();
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("date",date);
    modelAndView.setViewName("success");
    return modelAndView;
}

/*
 * pots请求  /test/handle
 */
@RequestMapping(value = "/handle",method = {RequestMethod.POST})
public ModelAndView handlePost(String username) {
    Date date = new Date();
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("date",date);
    modelAndView.setViewName("success");
    return modelAndView;
}


/*
 * put请求 /test/handle/15/lisi
 */
@RequestMapping(value = "/handle/{id}/{name}",method = {RequestMethod.PUT})
public ModelAndView handlePut(@PathVariable("id") Integer id,@PathVariable("name") String username) {
    Date date = new Date();
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("date",date);
    modelAndView.setViewName("success");
    return modelAndView;
}

/*
 * delete请求  /test/handle/15
 */
@RequestMapping(value = "/handle/{id}",method = {RequestMethod.DELETE})
public ModelAndView handleDelete(@PathVariable("id") Integer id) {
    Date date = new Date();
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("date",date);
    modelAndView.setViewName("success");
    return modelAndView;
}

web.xml中配置请求方式过滤器(将特定的post请求转换为put和delete请求)

<!--配置springmvc请求方式转换过滤器,会检查请求参数中是否有_method参数,如果有就按照指定的请求方式进行转换-->
<filter>
  <filter-name>hiddenHttpMethodFilter</filter-name>
  <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>hiddenHttpMethodFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

1.12 SpringMVC使用Json

Json交互
1)前端到后台:前端ajax发送json格式字符串,后台直接接收为pojo参数,使用注解@RequstBody
2)后台到前端:后台直接返回pojo对象,前端直接接收为json对象或者字符串,使用注解@ResponseBody

SpringMVC使用Json交互案例
1)引入jar包

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.9.0</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.0</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.9.0</version>
</dependency>

2)前端html代码

<div>
    <h2>Ajax json交互</h2>
    <fieldset>
        <input type="button" id="ajaxBtn" value="ajax提交"/>
    </fieldset>
</div>

3)前端js代码

<head>
    <title>SpringMVC 测试页</title>
    <script type="text/javascript" src="/js/jquery.min.js"></script>
    <script>
        $(function () {
            $("#ajaxBtn").bind("click",function () {
                // 发送ajax请求
                $.ajax({
                    url: '/demo/handle07',
                    type: 'POST',
                    data: '{"id":"1","name":"李四"}',
                    contentType: 'application/json;charset=utf-8',
                    dataType: 'json',
                    success: function (data) {
                        alert(data.name);
                    }
                })
            })
        })
    </script>
</head>

4)后台代码

@RequestMapping("/handle07")
// 添加@ResponseBody之后,不再走视图解析器那个流程,而是等同于response直接输出数据
public @ResponseBody User handle07(@RequestBody User user) {
    // 业务逻辑处理,修改name为张三丰
    user.setName("张三丰");
    return user;
}

2、SpringMVC高级技术

2.1 Servlet、过滤器、监听器、拦截器对比

分类 说明
Servlet 处理Request请求和Response响应
过滤器(Filter) 对Request请求起到过滤的作用,作用在Servlet之前,如果配置为/*可以对所有的资源访问(servlet、js/css静态资源等)进行过滤处理
监听器(Listener) 实现了javax.servlet.ServletContextListener接口的服务器端组件,它随Web应用的启动而启动,只初始化一次,然后会一直监视,随Web应用的停止而销毁
拦截器(Interceptor) 是SpringMVC、Struts等表现层框架自己的,不会拦截jsp/html/css/image的访问等,只会拦截访问的控制器方法(Handler)

注:
serlvet、filter、listener是配置在web.xml中的
interceptor是配置在表现层框架自己的配置文件中的(如:springmvc.xml)

关系图如下:
【java高级进阶笔记3】之springMVC

2.1 单个拦截器的执行流程

代码
后台代码,定义一个类实现HandlerInterceptor接口

/**
 * 自定义拦截器
 */
public class MyInteceptror01 implements HandlerInterceptor {

    /**
     * 会在handle方法业务逻辑执行之前执行
     * 一般处理权限校验逻辑
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInteceptror01  preHandle==========>");
        return true;
    }

    /**
     * 会在handle方法业务逻辑执行之后,未跳转页面之前执行
     * @param request
     * @param response
     * @param handler
     * @param modelAndView 封装了视图和数据
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInteceptror01  postHandle==========>");
    }

    /**
     * 会在跳转页面完毕之后执行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInteceptror01  afterCompletion==========>");
    }
}

springmvc中配置拦截器

<mvc:interceptors>
    <!--<bean class="com.lagou.edu.controller.inteceptror.MyInteceptror01"></bean>-->
    <mvc:interceptor>
        <!-- 配置拦截件的url,**代表当前目录下所有的url -->
        <mvc:mapping path="/**"/>
        <!-- 拦截排除的url -->
        <!--<mvc:exclude-mapping path="/demo/**"/>-->
        <bean class="com.lagou.edu.controller.inteceptror.MyInteceptror01" />
    </mvc:interceptor>
</mvc:interceptors>

执行流程

1)程序先执行preHandle()方法,如果该方法的返回值为true,则程序会继续向下执行处理器中的方法,否则将不再向下执行。
2)在业务处理器(即控制器Controller类)处理完请求后,会执行postHandle()方法,然后会通过DispatcherServlet向客户端返回响应。
3)在DispatcherServlet处理完请求后,才会执行afterCompletion()方法。

流程图
【java高级进阶笔记3】之springMVC

2.2 多个拦截器的执行流程

执行流程

1)preHandle()方法会按照配置文件中拦截器的配置顺序执行
2)postHandle()方法和afterCompletion()方法则会按照配置顺序的反序执行

流程图
【java高级进阶笔记3】之springMVC

2.3 处理multipart形式的数据(文件上传)

代码

pom.xml中引入jiar包

<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.1</version>
</dependency>

前端代码

<div>
    <h2>multipart 文件上传</h2>
    <fieldset>
        <form method="post" enctype="multipart/form-data" action="/demo/upload">
            <input type="file" name="uploadFile"/>
            <input type="submit" value="上传"/>
        </form>
    </fieldset>
</div>

springmvc.xml中增加解析器

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--设置上传文件大小上限,单位是字节,-1代表没有限制也是默认的-->
    <property name="maxUploadSize" value="5000000"/>
</bean>

后台代码

/**
 * 文件上传
 * @return
 */
@RequestMapping(value = "/upload")
public ModelAndView upload(MultipartFile uploadFile,HttpSession session) throws IOException {
    // 重命名,原名123.jpg ,获取后缀
    String originalFilename = uploadFile.getOriginalFilename();// 原始名称
    // 扩展名  jpg
    String ext = originalFilename.substring(originalFilename.lastIndexOf(".") + 1, originalFilename.length());
    String newName = UUID.randomUUID().toString() + "." + ext;

    // 存储,要存储到指定的文件夹,/uploads/yyyy-MM-dd,考虑文件过多的情况按照日期,生成一个子文件夹
    String realPath = session.getServletContext().getRealPath("/uploads");
    String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
    File folder = new File(realPath + "/" + datePath);

    if(!folder.exists()) {
        folder.mkdirs();
    }

    // 存储文件到目录
    uploadFile.transferTo(new File(folder,newName));

    // TODO 业务逻辑代码
    Date date = new Date();
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("date",date);
    modelAndView.setViewName("success");
    return modelAndView;
}

3、自定义简易版springmvc框架

3.1 思路

1、配置web.xml,加载自定义的servlet类(LagouDispatcherServlet

2、LagouDispatcherServlet初始化方法init
 1)加载配置文件 springmvc.properties
 2)扫描相关的类,扫描注解
 3)初始化bean对象(实现ioc容器,基于注解)
 4)实现依赖注入
 5)构造一个HandlerMapping处理器映射器,将配置好的urlMethod建立映射关系

3、LagouDispatcherServlet请求调用方法doGet/doPost
 1)根据url请求去map(handlerMapping)中找到对应的handel
 2)然后利用java反射机制调用(invoke)controller中的url对应的方法,传递对应的参数,并得到返回结果

3.1 代码

代码整体结构
【java高级进阶笔记3】之springMVC
核心代码

pom.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.example</groupId>
  <artifactId>mvc</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>mvc Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.9</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <!--编译插件定义编译细节-->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>utf-8</encoding>
          <!--告诉编译器,编译的时候记录下形参的真实名称-->
          <compilerArgs>
            <arg>-parameters</arg>
          </compilerArgs>
        </configuration>
      </plugin>
      <!-- tomcat插件 -->
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <port>8080</port>
          <path>/</path>
        </configuration>
      </plugin>

    </plugins>
  </build>
</project>

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>lagouDispatcherServlet</servlet-name>
    <servlet-class>com.lagou.edu.mvcaframework.servlet.LagouDispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath*:springmvc.properties</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>lagouDispatcherServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

LagouDispatcherServlet.java

package com.lagou.edu.mvcaframework.servlet;

import com.lagou.edu.mvcaframework.annotations.LagouAutowired;
import com.lagou.edu.mvcaframework.annotations.LagouController;
import com.lagou.edu.mvcaframework.annotations.LagouRequestMapping;
import com.lagou.edu.mvcaframework.annotations.LagouService;
import com.lagou.edu.projo.Handler;

import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LagouDispatcherServlet extends HttpServlet {

  private Properties properties = new Properties();

  private List<String> beanNames = new ArrayList<String>(); // beans权限的类名的集合

  // ioc容器
  private Map<String, Object> ioc = new HashMap<String, Object>();

  private List<Handler> handleMapping = new ArrayList<Handler>();

  @Override
  public void init(ServletConfig config) throws ServletException {

    String contextConfigLocation =
        config.getInitParameter("contextConfigLocation").replace("classpath*:", "");

    // 1 加载配置文件 springmvc.properties
    doLoadConfig(contextConfigLocation);

    // 2 扫描相关的类,扫描注解
    doScan(properties.getProperty("scanPackage"));

    // 3 初始化bean对象(实现ioc容器,基于注解)
    doInstance();

    // 4 实现依赖注入
    doAutoWired();

    // 5 构造一个HandlerMapping处理器映射器,将配置好的url和Method建立映射关系
    initHandlerMapping();

    System.out.println("lagout mvc 初始化完成......");
  }

  /** 构造一个HandlerMapping处理器映射器,将配置好的url和Method建立映射关系 */
  private void initHandlerMapping() {
    Set<Map.Entry<String, Object>> entries = ioc.entrySet();
    if (entries.isEmpty()) {
      return;
    }

    // 循环遍历
    for (Map.Entry<String, Object> entry : entries) {
      Class<?> aClass = entry.getValue().getClass();
      if (!aClass.isAnnotationPresent(LagouController.class)
          || !aClass.isAnnotationPresent(LagouRequestMapping.class)) {
        // 没有@LagouController注解和@LagouRequestMapping的类跳过,
        continue;
      }
      LagouRequestMapping requestMappingAnnotation =
          entry.getValue().getClass().getAnnotation(LagouRequestMapping.class);
      if (requestMappingAnnotation == null) {
        // 没有@LagouRequestMapping注解,跳过
        continue;
      }

      String bathUrl = requestMappingAnnotation.value();

      Method[] methods = aClass.getDeclaredMethods();
      if (methods == null || methods.length == 0) {
        continue;
      }

      // 循环遍历方法
      for (Method method : methods) {
        // 获取方法上的@LagouRequestMapping注解
        LagouRequestMapping methodAnnotation = method.getAnnotation(LagouRequestMapping.class);
        if (methodAnnotation == null) {
          continue;
        }

        String url = methodAnnotation.value();
        if (StringUtils.isBlank(url)) {
          continue;
        }

        String realUrl = bathUrl + url;

        // 构建Handlerd对象
        Handler handler = new Handler(entry.getValue(), method, Pattern.compile(realUrl));

        // 解析参数列表
        Parameter[] parameters = method.getParameters();

        Map<String, Integer> paramIndexMapping = new HashMap<String, Integer>();
        for (int i = 0; i < parameters.length; i++) {
          // 判断参数是否为HttpServletRequet,如果有
          String name = parameters[i].getType().getSimpleName();

          if ("HttpServletRequest".equals(name)) {
            paramIndexMapping.put("HttpServletRequest", 0);
          } else if ("HttpServletResponse".equals(name)) {
            paramIndexMapping.put("HttpServletResponse", 1);
          } else {
            paramIndexMapping.put(parameters[i].getName(), i);
          }
          handler.setParamIndexMapping(paramIndexMapping);
        }
        handleMapping.add(handler);
      }
    }
  }

  /** 实现依赖注入 */
  private void doAutoWired() {
    if (ioc.isEmpty()) return;

    for (Map.Entry<String, Object> entry : ioc.entrySet()) {
      String key = entry.getKey(); // 获取键(beanId)
      Object value = entry.getValue(); // 获取值(对象)

      // 获取类中的所有属性的值
      Field[] fields = value.getClass().getDeclaredFields();
      // 判断是为空,如果为空不处理
      if (fields != null && fields.length > 0) {
        for (Field declaredField : fields) {
          // 判断属性上是否有@LagouService注解
          if (declaredField.isAnnotationPresent(LagouAutowired.class)) {
            LagouAutowired autowiredAnnotation = declaredField.getAnnotation(LagouAutowired.class);

            String beanName = "";
            // 判断value是否有值
            if (StringUtils.isNotBlank(autowiredAnnotation.value())) {
              // value有值
              beanName = autowiredAnnotation.value();
            } else {
              // value没有值,取类名首字母小写
              beanName = fristLower(declaredField.getType().getSimpleName());
            }

            Object bean = ioc.get(beanName);
            declaredField.setAccessible(true);

            // 通过反射,进行属性注入
            try {
              declaredField.set(value, bean);
            } catch (IllegalAccessException e) {
              e.printStackTrace();
            }
          }
        }
      }
    }
  }

  /** 初始化bean对象(实现ioc容器,基于注解) */
  private void doInstance() {
    // 循环beanName集合
    for (String beanName : beanNames) {
      // 通过反射获取类
      try {
        Class<?> aClass = Class.forName(beanName);
        // 判断类上是否有@LagouController、@LagouService注解
        if (aClass.isAnnotationPresent(LagouController.class)) {
          // controller直接放到map中
          ioc.put(fristLower(aClass.getSimpleName()), aClass.newInstance());
        } else if (aClass.isAnnotationPresent(LagouService.class)) {
          // server要处理一下,判断是否有value属性
          // 获取类名首字母小写,并且获取接口的首字母小写
          LagouService annotation = aClass.getAnnotation(LagouService.class);
          String annotationValue = annotation.value();
          if (StringUtils.isNotBlank(annotationValue)) {
            // 如果有直接用value,如果没有
            ioc.put(annotationValue, aClass.newInstance());
          } else {
            ioc.put(fristLower(aClass.getSimpleName()), aClass.newInstance());
            // 获取类实现的接口
            Class<?>[] interfaces = aClass.getInterfaces();
            if (interfaces != null && interfaces.length > 0) {
              for (Class<?> anInterface : interfaces) {
                ioc.put(fristLower(anInterface.getSimpleName()), aClass.newInstance());
              }
            }
          }
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  /**
   * 类名首字符转小写
   *
   * @param beanName
   * @return
   */
  private String fristLower(String beanName) {
    String result =
        beanName.substring(0, 1).toLowerCase() + beanName.substring(1, beanName.length());
    return result;
  }

  /**
   * 扫描相关的类,扫描注解
   *
   * @param scanPackage
   */
  private void doScan(String scanPackage) {
    // 找到对应的C盘路径 com.lagou.edu.demo
    String path =
        Thread.currentThread().getContextClassLoader().getResource("").getPath()
            + scanPackage.replaceAll("\\.", "\\/");

    File file = new File(path);

    // 获取当前路径下的所有文件
    File[] files = file.listFiles();
    for (File tempFile : files) {
      // 判断当前记录是否为文件夹
      if (tempFile.isDirectory()) {
        // 是文件夹,迭代
        doScan(scanPackage + "." + tempFile.getName());
      } else if (tempFile.getName().endsWith(".class")) {
        String className = scanPackage + "." + tempFile.getName().replaceAll(".class", "");
        beanNames.add(className);
      }
    }
  }

  /**
   * 加载springmvc.properties配置文件
   *
   * @param contextConfigLocation
   */
  private void doLoadConfig(String contextConfigLocation) {
    InputStream resourceAsStream =
        this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
    try {
      properties.load(resourceAsStream);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    doPost(req, resp);
  }

  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    Handler handler = getHandler(req);

    if (handler == null) {
      resp.getWriter().write("404 not found");
      return;
    }

    Class<?>[] parameterTypes = handler.getMethod().getParameterTypes();

    // 根据上述数组长度创建一个新的数组(参数数组,是要传入反射调用的)
    Object[] paraValues = new Object[parameterTypes.length];

    Map<String, String[]> parameterMap = req.getParameterMap();

    // 遍历request中所有参数  (填充除了request,response之外的参数)
    for (Map.Entry<String, String[]> param : parameterMap.entrySet()) {
      // name=1&name=2   name [1,2]
      String value = StringUtils.join(param.getValue(), ","); // 如同 1,2

      // 如果参数和方法中的参数匹配上了,填充数据
      if (!handler.getParamIndexMapping().containsKey(param.getKey())) {
        continue;
      }

      // 方法形参确实有该参数,找到它的索引位置,对应的把参数值放入paraValues
      Integer index = handler.getParamIndexMapping().get(param.getKey()); // name在第 2 个位置

      paraValues[index] = value; // 把前台传递过来的参数值填充到对应的位置去
    }

    int requestIndex =
        handler.getParamIndexMapping().get(HttpServletRequest.class.getSimpleName()); // 0
    paraValues[requestIndex] = req;

    int responseIndex =
        handler.getParamIndexMapping().get(HttpServletResponse.class.getSimpleName()); // 1
    paraValues[responseIndex] = resp;

    try {
      handler.getMethod().invoke(handler.getController(), paraValues);
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      e.printStackTrace();
    }
  }

  // 获取handler
  private Handler getHandler(HttpServletRequest req) {
    // 从请求中获取url
    String requestURI = req.getRequestURI();
    if (handleMapping.isEmpty()) {
      return null;
    }

    for (Handler handler : handleMapping) {
      if (!handler.getPattern().matcher(requestURI).matches()) {
        continue;
      }
      return handler;
    }
    return null;
  }
}

4、SpringMVC源码剖析

4.1、前端控制器DispatcherServlet继承结构

【java高级进阶笔记3】之springMVC

4.1、初始化过程

  • tomcat启动: 加载应用的web.xml

【java高级进阶笔记3】之springMVC

  • 初始化DispatcherServlet

由tomcat调用DispatcherServlet的init方法,只会调用一次
【java高级进阶笔记3】之springMVC

  • 调用HttpServletBean的init方法
    【java高级进阶笔记3】之springMVC

  • 调用HttpServletBean的initServletBean方法(核心方法)
    【java高级进阶笔记3】之springMVC

  • 调用HttpServletBean的initWebApplicationContext方法(初始化ApplicationContext)
    【java高级进阶笔记3】之springMVC

  • 调用HttpServletBean的createWebApplicationContext方法
    【java高级进阶笔记3】之springMVC

  • 调用HttpServletBean的createWebApplicationContext方法
    【java高级进阶笔记3】之springMVC

  • 调用AbstractApplicationContext的refresh方法(IOC容器启动的核心方法)
    【java高级进阶笔记3】之springMVC

  • 中间成省略,最后会调用FrameworkServlet的onRefresh方法,完成九大组件的初始化
    【java高级进阶笔记3】之springMVC

4.1、初始化过程

  • 分析入口:FrameworkServlet中的service方法
    【java高级进阶笔记3】之springMVC

  • 调用FrameworkServlet中的doGet方法
    【java高级进阶笔记3】之springMVC

  • 调用FrameworkServlet中的processRequest方法
    【java高级进阶笔记3】之springMVC

  • 调用DispatcherServlet中的doService方法
    【java高级进阶笔记3】之springMVC

  • 调用DispatcherServlet中的doDispatch方法(核心方法)
    【java高级进阶笔记3】之springMVC

5、SSM整合

5.1、整合策略

SSM = Spring + SpringMVC + Mybatis = (Spring + Mybatis)+ SpringMVC
先整合 Spring + Mybatis
然后再整合 SpringMVC

5.2、Mybatis整合Spring

整合目标

  • 数据库连接池以及事务管理都交给Spring容器来完成
  • SqlSessionFactory对象应该放到Spring容器中作为单例对象管理
  • Mapper动态代理对象交给Spring管理,我们从Spring容器中直接获得Mapper的代理对象

整合目标

  • Junit测试jar(4.12版本)
  • Mybatis的jar(3.4.5)
  • Spring相关jar(spring-contextspring-testspring-jdbcspring-txspring-aopaspectjweaver
  • Mybatis/Spring整合包jar(mybatis-spring-xx.jar
  • Mysql数据库驱动jar
  • Druid数据库连接池的jar

5.3、整合SpringMVC

整合思路

  • 在Mybatis整合Spring的基础上开发一个SpringMVC的入门案例

5.3、整合后代码

代码整体结构
【java高级进阶笔记3】之springMVC

pom.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>com.lagou.edu</groupId>
  <artifactId>ssm</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>ssm Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <!--junit-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <!--mybatis-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.5</version>
    </dependency>
    <!--spring相关-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.1.12.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.1.12.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.1.12.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.1.12.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.1.12.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.9</version>
    </dependency>
    <!--mybatis与spring的整合包-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.3</version>
    </dependency>
    <!--数据库驱动jar-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.46</version>
    </dependency>
    <!--druid连接池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.21</version>
    </dependency>


    <!--SpringMVC-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.1.12.RELEASE</version>
    </dependency>
    <!--jsp-api&servlet-api-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!--页面使用jstl表达式-->
    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>taglibs</groupId>
      <artifactId>standard</artifactId>
      <version>1.1.2</version>
    </dependency>

    <!--json数据交互所需jar,start-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.0</version>
    </dependency>
    <!--json数据交互所需jar,end-->
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <port>8080</port>
          <path>/</path>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

web.xml文件

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:applicationContext*.xml</param-value>
  </context-param>
  <!--spring框架启动-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!--springmvc启动-->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath*:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

jdbc.properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://ip:3306/test_yuyz
jdbc.username=
jdbc.password=

springmvc.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--扫描controller-->
    <context:component-scan base-package="com.lagou.edu.controller"/>

    <!--配置springmvc注解驱动,自动注册合适的组件handlerMapping和handlerAdapter-->
    <mvc:annotation-driven/>
</beans>

applicationContext-dao.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
						http://www.springframework.org/schema/beans/spring-beans.xsd
						http://www.springframework.org/schema/context
						http://www.springframework.org/schema/context/spring-context.xsd">

    <!--数据库连接池以及事务管理都交给Spring容器来完成-->
    <!--引⼊外部资源⽂件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--第三⽅jar中的bean定义在xml中-->
    <bean id="dataSource"
          class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--包扫描-->
    <context:component-scan base-package="com.lagou.edu.mapper"/>

    <!--SqlSessionFactory对象应该放到Spring容器中作为单例对象管理-->
    <bean id="sqlSessionFactory"
          class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--别名映射扫描-->
        <property name="typeAliasesPackage" value="com.lagou.edu.pojo"/>
        <!--数据源dataSource-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--Mapper动态代理对象交给Spring管理,我们从Spring容器中直接获得Mapper的代理对象-->
    <!--扫描mapper接⼝,⽣成代理对象,⽣成的代理对象会存储在ioc容器中-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--mapper接⼝包路径配置-->
        <property name="basePackage" value="com.lagou.edu.mapper"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>
</beans>

applicationContext-service.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
						http://www.springframework.org/schema/beans/spring-beans.xsd
						http://www.springframework.org/schema/context
						http://www.springframework.org/schema/context/spring-context.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx.xsd">
    
    <!--包扫描-->
    <context:component-scan base-package="com.lagou.edu.service"/>

    <!--事务管理-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--事务管理注解驱动-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

AccountMapper.xml文件

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lagou.edu.mapper.AccountMapper">
    <select id="queryAccountList" resultType="com.lagou.edu.pojo.Account">
        select * from account
    </select>
</mapper>

AccountController.java文件

package com.lagou.edu.controller;

import com.lagou.edu.pojo.Account;
import com.lagou.edu.service.AccountService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

@Controller
@RequestMapping("/account")
public class AccountController {

    @Autowired
    private AccountService accountService;

    @RequestMapping("/queryAll")
    @ResponseBody
    public List<Account> queryAll() throws Exception {
       return accountService.queryAccountList();
    }
}

AccountService.java文件

package com.lagou.edu.service;

import com.lagou.edu.pojo.Account;

import java.util.List;

public interface AccountService {

    /**
     * 查询所有账户信息
     * @return
     * @throws Exception
     */
    public List<Account> queryAccountList() throws Exception;
}

AccountServiceImpl.java文件

package com.lagou.edu.service.impl;

import com.lagou.edu.mapper.AccountMapper;
import com.lagou.edu.pojo.Account;
import com.lagou.edu.service.AccountService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountMapper accountMapper;

    @Override
    public List<Account> queryAccountList() throws Exception {
        return accountMapper.queryAccountList();
    }
}

AccountMapper.java文件

package com.lagou.edu.mapper;

import com.lagou.edu.pojo.Account;

import java.util.List;

public interface AccountMapper {

    /**
     * 查询所有账户信息
     * @return
     * @throws Exception
     */
    public List<Account> queryAccountList() throws Exception;
}

Account.java文件

package com.lagou.edu.pojo;

public class Account {

    private String cardNo;
    private String name;
    private Integer money;

    public String getCardNo() {
        return cardNo;
    }

    public void setCardNo(String cardNo) {
        this.cardNo = cardNo;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getMoney() {
        return money;
    }

    public void setMoney(Integer money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "cardNo='" + cardNo + '\'' +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

数据库建表语句

CREATE TABLE `account` (
  `cardNo` varchar(50) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `money` int(255) DEFAULT NULL,
  PRIMARY KEY (`cardNo`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

本文地址:https://blog.csdn.net/yuyangzhi10/article/details/109371707