前置知识

Header详解

HTTP(HyperTextTransferProtocol)即超文本传输协议,目前网页传输的的通用协议。HTTP协议采用了请求/响应模型,浏览器或其他客户端发出请求,服务器给与响应。就整个网络资源传输而言,包括message-header和message-body两部分。首先传递message- header,即http header消息 http header 消息通常被分为4个部分:general header, request header, response header, entity header。但是这种分法就理解而言,感觉界限不太明确。根据维基百科对http header内容的组织形式,大体分为Request和Response两部分。

Requests部分

Header 解释 示例
Accept 指定客户端能够接收的内容类型 Accept: text/plain, text/html
Accept-Charset 浏览器可以接受的字符编码集。 Accept-Charset: iso-8859-5
Accept-Encoding 指定浏览器可以支持的web服务器返回内容压缩编码类型。 Accept-Encoding: compress, gzip
Accept-Language 浏览器可接受的语言 Accept-Language: en,zh
Accept-Ranges 可以请求网页实体的一个或者多个子范围字段 Accept-Ranges: bytes
Authorization HTTP授权的授权证书 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Cache-Control 指定请求和响应遵循的缓存机制 Cache-Control: no-cache
Connection 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) Connection: close
Cookie HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 Cookie: $Version=1; Skin=new;
Content-Length 请求的内容长度 Content-Length: 348
Content-Type 请求的与实体对应的MIME信息 Content-Type: application/x-www-form-urlencoded
Date 请求发送的日期和时间 Date: Tue, 15 Nov 2010 08:12:31 GMT
Expect 请求的特定的服务器行为 Expect: 100-continue
From 发出请求的用户的Email From: user@email.com
Host 指定请求的服务器的域名和端口号 Host: www.zcmhi.com
If-Match 只有请求内容与实体相匹配才有效 If-Match: “737060cd8c284d8af7ad3082f209582d”
If-Modified-Since 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT
If-None-Match 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 If-None-Match: “737060cd8c284d8af7ad3082f209582d”
If-Range 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag If-Range: “737060cd8c284d8af7ad3082f209582d”
If-Unmodified-Since 只在实体在指定时间之后未被修改才请求成功 If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT
Max-Forwards 限制信息通过代理和网关传送的时间 Max-Forwards: 10
Pragma 用来包含实现特定的指令 Pragma: no-cache
Proxy-Authorization 连接到代理的授权证书 Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Range 只请求实体的一部分,指定范围 Range: bytes=500-999
Referer 先前网页的地址,当前请求网页紧随其后,即来路 Referer: http://www.zcmhi.com/archives/71.html
TE 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 TE: trailers,deflate;q=0.5
Upgrade 向服务器指定某种传输协议以便服务器进行转换(如果支持) Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
User-Agent User-Agent的内容包含发出请求的用户信息 User-Agent: Mozilla/5.0 (Linux; X11)
Via 通知中间网关或代理服务器地址,通信协议 Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
Warning 关于消息实体的警告信息 Warn: 199 Miscellaneous warning

Responses 部分

Header 解释 示例
Accept-Ranges 表明服务器是否支持指定范围请求及哪种类型的分段请求 Accept-Ranges: bytes
Age 从原始服务器到代理缓存形成的估算时间(以秒计,非负) Age: 12
Allow 对某网络资源的有效的请求行为,不允许则返回405 Allow: GET, HEAD
Cache-Control 告诉所有的缓存机制是否可以缓存及哪种类型 Cache-Control: no-cache
Content-Encoding web服务器支持的返回内容压缩编码类型。 Content-Encoding: gzip
Content-Language 响应体的语言 Content-Language: en,zh
Content-Length 响应体的长度 Content-Length: 348
Content-Location 请求资源可替代的备用的另一地址 Content-Location: /index.htm
Content-MD5 返回资源的MD5校验值 Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==
Content-Range 在整个返回体中本部分的字节位置 Content-Range: bytes 21010-47021/47022
Content-Type 返回内容的MIME类型 Content-Type: text/html; charset=utf-8
Date 原始服务器消息发出的时间 Date: Tue, 15 Nov 2010 08:12:31 GMT
ETag 请求变量的实体标签的当前值 ETag: “737060cd8c284d8af7ad3082f209582d”
Expires 响应过期的日期和时间 Expires: Thu, 01 Dec 2010 16:00:00 GMT
Last-Modified 请求资源的最后修改时间 Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT
Location 用来重定向接收方到非请求URL的位置来完成请求或标识新的资源 Location: http://www.zcmhi.com/archives/94.html
Pragma 包括实现特定的指令,它可应用到响应链上的任何接收方 Pragma: no-cache
Proxy-Authenticate 它指出认证方案和可应用到代理的该URL上的参数 Proxy-Authenticate: Basic
refresh 应用于重定向或一个新的资源被创造,在5秒之后重定向(由网景提出,被大部分浏览器支持) Refresh: 5; url=http://www.zcmhi.com/archives/94.html
Retry-After 如果实体暂时不可取,通知客户端在指定时间之后再次尝试 Retry-After: 120
Server web服务器软件名称 Server: Apache/1.3.27 (Unix) (Red-Hat/Linux)
Set-Cookie 设置Http Cookie Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1
Trailer 指出头域在分块传输编码的尾部存在 Trailer: Max-Forwards
Transfer-Encoding 文件传输编码 Transfer-Encoding:chunked
Vary 告诉下游代理是使用缓存响应还是从原始服务器请求 Vary: *
Via 告知代理客户端响应是通过哪里发送的 Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
Warning 警告实体可能存在的问题 Warning: 199 Miscellaneous warning
WWW-Authenticate 表明客户端请求实体应该使用的授权方案 WWW-Authenticate: Basic
Content-Disposition 指示客户端下载文件 attachment;filename=“filename.xls”

什么是三层架构

什么是系统架构

1
2
   所谓系统架构是指,整合应用系统程序大的结构。经常提到的系统结构有两种:
   三层架构与 MVC。这两种结构既有区别,又有联系。但这两种结构的使用,均是为了降低系统模块间的耦合度

什么是三层架构

1
2
三层架构是指:视图层 View、服务层 Service,与持久层 DAO。它们分别完成不同的功能。

  • View 层:用于接收用户提交请求的代码
  • Service 层:系统的业务逻辑主要在这里完成
  • DAO 层:直接操作数据库的代码
1
2
3
4
   为了更好的降低各层间的耦合度,在三层架构程序设计中,采用面向抽象编程。
   即上层对下层的调用,是通过接口实现的。
   而下层对上层的真正服务提供者,是下层接口的实现类。
   服务标准(接口)是相同的,服务提供者(实现类)可以更换。这就实现了层间解耦合。

image-20230922140715785

002_什么是 MVC 模式

什么是 MVC 模式

概述

1
MVC,即 Model 模型、View 视图,及 Controller 控制器。
  • View:视图,为用户提供使用界面,与用户直接进行交互。
  • Model:模型,承载数据,并对用户提交请求进行计算的模块。其分为两类,一类称为数据承载 Bean,一类称为业务处理 Bean。所谓数据承载 Bean 是指实体类,专门用户承载业务数据的,如 Student、User 等。而业务处理 Bean 则是指 Service 或 Dao 对象, 专门用于处理用户提交请求的。
  • Controller:控制器,用于将用户请求转发给相应的 Model 进行处理,并根据 Model 的计算结果向用户提供相应响应

MVC 架构程序的工作流程

  • 用户通过 View 页面向服务端提出请求,可以是表单请求、超链接请求、AJAX 请求等
  • 服务端 Controller 控制器接收到请求后对请求进行解析,找到相应的 Model 对用户请求进行处理
  • Model 处理后,将处理结果再交给 Controller
  • Controller 在接到处理结果后,根据处理结果找到要作为向客户端发回的响应 View 页面。页面经渲染(数据填充)后,再发送给客户端。

image-20230922140721931

三层架构 + MVC 示意图

image-20230922140726833

开闭合离最单依

开闭合离最单依

1
2
3
1.面向对象设计原则
2.重构原则(重构也是为了解耦,业务在不断地变化,为了赶进度。有时候没时间想是不是符合这些原则。所以,有个重构原则。)
事不过三,三则重构

MVC体会

1.为什么要做架构?

系统架构,全局观,大局观,决定你的产品能走多远,技术支撑,能抗多少并发,能处理多大的业务量。这都是从底层的系统架构开发。

比如,假如支付宝做系统架构可以每秒做1000W次交易。如果你不做架构,你系统每秒能做多少次交易,你根本不知道,也不能支撑。

三层架构是架构的一种,还有比如微服务架构等。mvc三层架构,用于单体应用足够了。

代码越写越多,系统的复杂度越来越高。

复杂度=耦合度。

做系统的架构就是降低系统之间的耦合度,降低系统之间的复杂度。

2.三层架构长什么样?

>视图层:和用户交互

>业务逻辑层: Service

(不是说一定要叫service,你叫manager也可以。但是约定大于配置。协同开发,你乱起就会增加沟通成本,交流有障碍。)

>数据访问层: DAO

数据不一定存在数据库啊,也可以存文件,但是,随着业务的复杂,有一些特殊需求,比如,你一个文件存用户,一个文件存金额。然后你用io流去一行一行读,这样效率太低了。难道你只能一行一行检索吗?数据库就出来了。而且,你文件放那边,谁都能看,所以,还有个安全问题。)

3.做开发,业务才是核心。

怎么让查的快一点,怎么让别人不能轻易攻击,这是技术。

技术是辅助业务的。

4.业务是有复杂度,复杂度等于耦合度。事务和业务相关。

复杂度是分等级的

- 简单业务 : 只开启一个事务

- 普通业务 : 开启3个事务

- 复杂业务 : 开启7个事务(非常的复杂,恶心,一定要想办法解耦)

耦合度:多张表之间有个依赖关系,你该一张表,你另外的表也要改。

模块与模块之间,系统和系统之间存在强关联性。

降低耦合,就是降低关联性,弱关联性。

只能降低,耦合一定是存在的,一定有依赖,有关联,至少数据库表你最起码要依赖数据库。这就是耦合。所以,只能使降低耦合。让业务尽量简单。

5.三层结构可以降低每一层之间的耦合

- 一个类只做一种事(高内聚)

- 一个方法只做一件事

- 写且只写一次

MVC模式

6.Model    角色

  • 数据模型: Entity
  • 业务模型: Service

7.Controller :  控制器  :   Servlet

  • 处理用户请求的

       

Servlet 服务器小程序 out.print     --  耦合度高,可读性差  

    (既要处理业务逻辑,又要处理业务展示。这是不符合,一个类只做一种事。内聚↓,耦合↑)

所以JSP出现了

  1. View   视图   JSP

JSP 处理页面展示  (jsp就是servlet)。把页面展示和业务逻辑分离。解耦合

   降低耦合度,降低复杂度

   jsp能把servlet中的页面展示功能分离出来,这就是一门技术。

MVC模式是视图层的模式

Spring MVC 简介

概述

Spring MVC 也叫 Spring Web MVC ,属于展示层框架。SpringMVC 是 Spring 框架的一部分。

Spring Web MVC 框架提供了 MVC (模型 - 视图 - 控制器) 架构和用于开发灵活和松散耦合的 Web 应用程序的组件。 MVC 模式导致应用程序的不同方面(输入逻辑,业务逻辑和 UI 逻辑)分离,同时提供这些元素之间的松散耦合。

  • 模型 (Model):封装了应用程序数据,通常它们将由 POJO 类组成。
  • 视图 (View):负责渲染模型数据,一般来说它生成客户端浏览器可以解释 HTML 输出。
  • 控制器 (Controller):负责处理用户请求并构建适当的模型,并将其传递给视图进行渲染。

DispatcherServlet 组件类

Spring Web MVC 框架是围绕 DispatcherServlet 设计的,它处理所有的 HTTP 请求和响应。 Spring Web MVC DispatcherServlet 的请求处理工作流如下图所示:

image-20230922140733888

以下是对应于到 DispatcherServlet 的传入 HTTP 请求的事件顺序:

  • 在接收到 HTTP 请求后,DispatcherServlet 会查询 HandlerMapping 以调用相应的 Controller。
  • Controller 接受请求并根据使用的 GET 或 POST 方法调用相应的服务方法。 服务方法将基于定义的业务逻辑设置模型数据,并将视图名称返回给 DispatcherServlet。
  • DispatcherServlet 将从 ViewResolver 获取请求的定义视图。
  • 当视图完成,DispatcherServlet 将模型数据传递到最终的视图,并在浏览器上呈现。

所有上述组件,即: HandlerMapping,Controller 和 ViewResolver 是 WebApplicationContext 的一部分,它是普通 ApplicationContext 的扩展,带有 Web 应用程序所需的一些额外功能。

Spring MVC 整合 Spring

POM

在 pom.xml 配置文件中增加 org.springframework:spring-webmvc 依赖

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.17.RELEASE</version>
</dependency>

配置 web.xml

CharacterEncodingFilter

配置字符集过滤器,用于解决中文编码问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

DispatcherServlet

配置 Spring 的 Servlet 分发器处理所有 HTTP 的请求和响应

1
2
3
4
5
6
7
8
9
10
11
12
13
<servlet>
    <servlet-name>springServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:/spring-mvc*.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

配置 Spring MVC

创建一个名为 spring-mvc.xml 文件来配置 MVC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <description>Spring MVC Configuration</description>
    <!-- 加载配置属性文件 -->
    <context:property-placeholder ignore-unresolvable="true" location="classpath:myshop.properties" />
    <!-- 使用 Annotation 自动注册 Bean,只扫描 @Controller -->
    <context:component-scan base-package="com.lusifer.myshop" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>
    <!-- 默认的注解映射的支持 -->
    <mvc:annotation-driven />
    <!-- 定义视图文件解析 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="${web.view.prefix}" />
        <property name="suffix" value="${web.view.suffix}" />
    </bean>
    <!-- 静态资源映射 -->
    <mvc:resources mapping="/static/**" location="/static/" cache-period="31536000" />
</beans>

相关配置说明:

  • context:property-placeholder
  • context:component-scan
  • InternalResourceViewResolver
    • prefix
    • suffix
  • mvc:resources

系统相关配置

在 spring-mvc.xnl 中,我们配置了 <context:property-placeholder ignore-unresolvable=”true” location=”classpath:myshop.properties”/> 用于动态加载属性配置文件,实际开发中我们会将系统所需的一些配置信息封装到 .properties 配置文件中便于统一的管理。

创建一个名为 myshop.properties 的配置文件,内容如下:

1
2
3
4
5
6
7
#============================#
#==== Framework settings ====#
#============================#

# 视图文件存放路径
web.view.prefix=/WEB-INF/views/
web.view.suffix=.jsp

去掉 Spring 配置的重复扫描

由于 spring-mvc.xml 中已经配置了 @Controller 注解的扫描而 spring-context.xml 中配置的是扫描全部注解,故在这里需要将 @Controller 注解的扫描配置排除。

修改 spring-context.xml 配置:

1
2
3
4
<!-- 使用 Annotation 自动注册 Bean,在主容器中不扫描 @Controller 注解,在 SpringMVC 中只扫描 @Controller 注解。-->
<context:component-scan base-package="com.funtl.my.shop">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

Spring MVC 第一个Controller

概述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.funtl.my.shop.web.controller;

import com.funtl.my.shop.service.UserService;
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.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class LoginController {

@Autowired
private UserService userService;

@RequestMapping(value = {"", "login"}, method = RequestMethod.GET)
public String login() {
return "login";
}

@RequestMapping(value = "login", method = RequestMethod.POST)
public String login(@RequestParam(required = true) String email, @RequestParam(required = true)     String password) {
return "redirect:/main";
}
}

注解说明

@Controller

在 Spring MVC 中,控制器 Controller 负责处理由 DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个 Model ,然后再把该 Model 返回给对应的 View 进行展示。在 Spring MVC 中提供了一个非常简便的定义 Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用 @Controller 标记一个类是 Controller ,然后使用 @RequestMapping 和 @RequestParam 等一些注解用以定义 URL 请求和 Controller 方法之间的映射,这样的 Controller 就能被外界访问到。此外 Controller 不会直接依赖于 HttpServletRequest 和 HttpServletResponse 等 HttpServlet 对象,它们可以通过 Controller 的方法参数灵活的获取到。

@Controller 用于标记在一个类上,使用它标记的类就是一个 Spring MVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了 @RequestMapping 注解。@Controller 只是定义了一个控制器类,而使用 @RequestMapping 注解的方法才是真正处理请求的处理器。

@RequestMapping

RequestMapping 是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

RequestMapping 注解有六个属性:

  • value, method
    • value:指定请求的实际地址,指定的地址可以是 URI Template 模式
    • method:指定请求的method类型, GET、POST、PUT、DELETE 等
  • consumes,produces
    • consumes:指定处理请求的提交内容类型(Content-Type),例如 application/json, text/html
    • produces: 指定返回的内容类型,仅当 request 请求头中的(Accept)类型中包含该指定类型才返回
  • params,headers
    • params:指定 request 中必须包含某些参数值是,才让该方法处理
    • headers:指定 request 中必须包含某些指定的 header 值,才能让该方法处理请求

Spring MVC Maven模块化开发

概述

在多人协同开发时,特别是规模较大的项目,为了方便日后的代码维护和管理,我们会将每个开发人员的工作细分到具体的功能和模块上。随着项目的不断扩大,模块也会越来越多,后续会更加难以维护和扩展,为了应对这种情况后期我们还会采用微服务架构的方式进行开发。

以当前教程为例,我们可以将模块划分为如下形式:

  • 统一的依赖管理(dependencies)
  • 通用的工具类(commons)
  • 领域模型(domain)
  • 管理后台(admin)
  • 商城前端(ui)
  • 接口模块(api)

整个模块化开发过程主要是在开发思想上稍作了一些转变,只需要按照下面的流程操作即可。

创建根项目(工程)

创建一个名为 my-shop 的工程,pom.xml 文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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.funtl</groupId>
    <artifactId>my-shop</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
         
    </modules>
</project>

该项目称之为 Root 项目,主要作用是管理整个工程的全部模块,当有新模块加入时需要在 modules 元素下配置对应的模块目录

创建统一的依赖管理

创建一个名为 my-shop-dependencies 的项目,pom.xml 文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<?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>
    <parent>
        <groupId>com.funtl</groupId>
        <artifactId>my-shop</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>my-shop-dependencies</artifactId>
    <packaging>pom</packaging>
    <name>my-shop-dependencies</name>
    <description></description>
    <properties>
        <!-- 环境配置 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <!-- 统一的依赖管理 -->
        <commons-lang3.version>3.5</commons-lang3.version>
        <jstl.version>1.2</jstl.version>
        <log4j.version>1.2.17</log4j.version>
        <servlet-api.version>3.1.0</servlet-api.version>
        <slf4j.version>1.7.25</slf4j.version>
        <spring.version>4.3.17.RELEASE</spring.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <!-- Spring Begin -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <!-- Spring End -->
            <!-- Servlet Begin -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>${servlet-api.version}</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>${jstl.version}</version>
            </dependency>
            <!-- Servlet End -->
            <!-- Log Begin -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>jcl-over-slf4j</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>jul-to-slf4j</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <!-- Log End -->
            <!-- Commons Begin -->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>${commons-lang3.version}</version>
            </dependency>
            <!-- Commons End -->
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <!-- Compiler 插件, 设定 JDK 版本 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                    <showWarnings>true</showWarnings>
                </configuration>
            </plugin>
        </plugins>
        <!-- 资源文件配置 -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
    </build>
</project>

PS:别忘记在 my-shop 工程的 pom.xml 中增加 <module>my-shop-dependencies</module> 配置

创建通用的工具类

创建一个名为 my-shop-commons 的项目,pom.xml 文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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>
    <parent>
        <groupId>com.funtl</groupId>
        <artifactId>my-shop-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../my-shop-dependencies/pom.xml</relativePath>
    </parent>
    <artifactId>my-shop-commons</artifactId>
    <packaging>jar</packaging>
    <name>my-shop-commons</name>
    <description></description>
</project>

PS:别忘记在 my-shop 工程的 pom.xml 中增加 <module>my-shop-commons</module> 配置

创建领域模型

创建一个名为 my-shop-domain 的项目,pom.xml 文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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>
    <parent>
        <groupId>com.funtl</groupId>
        <artifactId>my-shop-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../my-shop-dependencies/pom.xml</relativePath>
    </parent>
    <artifactId>my-shop-domain</artifactId>
    <packaging>jar</packaging>
    <name>my-shop-domain</name>
    <description></description>
</project>

PS:别忘记在 my-shop 工程的 pom.xml 中增加 <module>my-shop-domain</module> 配置

创建管理后台

创建一个名为 my-shop-web-admin 的项目,pom.xml 文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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>
    <parent>
        <groupId>com.funtl</groupId>
        <artifactId>my-shop-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../my-shop-dependencies/pom.xml</relativePath>
    </parent>
    <artifactId>my-shop-web-admin</artifactId>
    <packaging>war</packaging>
    <name>my-shop-web-admin</name>
    <description></description>
    <dependencies>
        <dependency>
            <groupId>com.funtl</groupId>
            <artifactId>my-shop-commons</artifactId>
            <version>${project.parent.version}</version>
        </dependency>
        <dependency>
            <groupId>com.funtl</groupId>
            <artifactId>my-shop-domain</artifactId>
            <version>${project.parent.version}</version>
        </dependency>
    </dependencies>
</project>

PS:别忘记在 my-shop 工程的 pom.xml 中增加 <module>my-shop-web-admin</module> 配置

创建商城前端

创建一个名为 my-shop-web-ui 的项目,pom.xml 文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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>
    <parent>
        <groupId>com.funtl</groupId>
        <artifactId>my-shop-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../my-shop-dependencies/pom.xml</relativePath>
    </parent>
    <artifactId>my-shop-web-ui</artifactId>
    <packaging>war</packaging>
    <name>my-shop-web-ui</name>
    <description></description>
    <dependencies>
        <dependency>
            <groupId>com.funtl</groupId>
            <artifactId>my-shop-commons</artifactId>
            <version>${project.parent.version}</version>
        </dependency>
    </dependencies>
</project>

PS:别忘记在 my-shop 工程的 pom.xml 中增加 <module>my-shop-web-ui</module> 配置

创建接口模块

创建一个名为 my-shop-web-api 的项目,pom.xml 文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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>
    <parent>
        <groupId>com.funtl</groupId>
        <artifactId>my-shop-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../my-shop-dependencies/pom.xml</relativePath>
    </parent>
    <artifactId>my-shop-web-api</artifactId>
    <packaging>war</packaging>
    <name>my-shop-web-api</name>
    <description></description>
    <dependencies>
        <dependency>
            <groupId>com.funtl</groupId>
            <artifactId>my-shop-commons</artifactId>
            <version>${project.parent.version}</version>
        </dependency>
    </dependencies>
</project>

PS:别忘记在 my-shop 工程的 pom.xml 中增加 <module>my-shop-web-api</module> 配置

清理、编译、打包

至此一个完整的模块化工程创建完毕,此时的 Root 工程 pom.xml 文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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.funtl</groupId>
    <artifactId>my-shop</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>my-shop-dependencies</module>
        <module>my-shop-commons</module>
        <module>my-shop-domain</module>
        <module>my-shop-web-admin</module>
        <module>my-shop-web-ui</module>
        <module>my-shop-web-api</module>
    </modules>
</project>

我们可以在 Root 工程中使用 Maven 提供的 mvn clean 命令测试一下效果,控制台输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] my-shop
[INFO] my-shop-dependencies
[INFO] my-shop-commons
[INFO] my-shop-domain
[INFO] my-shop-web-admin
[INFO] my-shop-web-ui
[INFO] my-shop-web-api
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building my-shop 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ my-shop ---
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building my-shop-dependencies 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ my-shop-dependencies ---
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building my-shop-commons 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ my-shop-commons ---
[INFO] Deleting D:\Workspace\my-shop\my-shop-commons\target
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building my-shop-domain 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ my-shop-domain ---
[INFO] Deleting D:\Workspace\my-shop\my-shop-domain\target
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building my-shop-web-admin 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ my-shop-web-admin ---
[INFO] Deleting D:\Workspace\my-shop\my-shop-web-admin\target
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building my-shop-web-ui 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ my-shop-web-ui ---
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building my-shop-web-api 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ my-shop-web-api ---
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] my-shop ............................................ SUCCESS [ 0.158 s]
[INFO] my-shop-dependencies ............................... SUCCESS [ 0.004 s]
[INFO] my-shop-commons .................................... SUCCESS [ 0.020 s]
[INFO] my-shop-domain ..................................... SUCCESS [ 0.016 s]
[INFO] my-shop-web-admin .................................. SUCCESS [ 0.033 s]
[INFO] my-shop-web-ui ..................................... SUCCESS [ 0.012 s]
[INFO] my-shop-web-api .................................... SUCCESS [ 0.008 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.400 s
[INFO] Finished at: 2018-06-12T07:47:58+08:00
[INFO] Final Memory: 8M/241M
[INFO] ------------------------------------------------------------------------

Spring MVC 表单标签库

为什么用?

如果不用,我们保存表单失败的时候,想要把表单的值留着,我们就得写一堆${user.username}代码,来回显表单的值。所以,为了简化代码。

声明表单标签库

在使用 SpringMVC 的时候我们可以使用 Spring 封装的一系列表单标签,这些标签都可以访问到 ModelMap 中的内容。我们需要先在 JSP 中声明使用的标签,具体做法是在 JSP 文件的顶部加入以下指令:

1
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

表单标签

<form:form />

使用 Spring MVC 的 form 标签主要有两个作用,第一是它会自动的绑定来自 Model 中的一个属性值到当前 form 对应的实体对象,默认是 command 属性,这样我们就可以在 form 表单体里面方便的使用该对象的属性了。第二是它支持我们在提交表单的时候使用除 GET 和 POST 之外的其他方法进行提交,包括 DELETE 和 PUT 等。

1
2
3
4
5
6
7
8
9
10
11
12
13
<form:form action="formTag/form.do" method="post">  
<table>
<tr>
<td>Name:</td><td><form:input path="name"/></td>
</tr>
<tr>
<td>Age:</td><td><form:input path="age"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="提交"/></td>
</tr>
</table>
</form:form>

文本框

<form:input />

使用 <form:input path="name" /> 标签来渲染一个 HTML 文本框,等同于:

1
<input id="name" name="name" type="text" value=""/>

密码框

<form:password />

使用 <form:password path="password" /> 标签来渲染一个 HTML 密码框,等同于:

1
<input id="password" name="password" type="password" value=""/>

文本域

<form:textarea />

使用 <form:textarea path="address" rows="5" cols="30" /> 标签来渲染一个 HTML 文本域,等同于:

1
<textarea id="address" name="address" rows="5" cols="30">

复选框

<form:checkbox />

使用 <form:checkbox path="receivePaper" /> 标签来渲染一个 HTML 复选框,等同于:

1
2
<input id="receivePaper1" name="receivePaper" type="checkbox" value="true"/>
<input type="hidden" name="_receivePaper" value="on"/>

复选框(多选)

<form:checkboxes />

使用 <form:checkboxes items="${webFrameworkList}" path="favoriteFrameworks" /> 标签来渲染一个 HTML 多选复选框,等同于:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<span>
<input id="favoriteFrameworks1" name="favoriteFrameworks" type="checkbox" value="Spring MVC" checked="checked"/>
<label for="favoriteFrameworks1">Spring MVC</label>
</span>
<span>
<input id="favoriteFrameworks2" name="favoriteFrameworks" type="checkbox" value="Struts 1"/>
<label for="favoriteFrameworks2">Struts 1</label>
</span>
<span>
<input id="favoriteFrameworks3" name="favoriteFrameworks" type="checkbox" value="Struts 2" checked="checked"/>
<label for="favoriteFrameworks3">Struts 2</label>
</span>
<span>
<input id="favoriteFrameworks4" name="favoriteFrameworks" type="checkbox" value="Apache Wicket"/>
<label for="favoriteFrameworks4">Apache Wicket</label>
</span>
<input type="hidden" name="_favoriteFrameworks" value="on"/>

单选按钮

<form:radiobutton />

使用 <form:radiobutton /> 标签来渲染一个 HTML 单选按钮,等同于:

1
2
<form:radiobutton path="gender" value="M" label="男" />
<form:radiobutton path="gender" value="F" label="女" />
1
2
<input id="gender1" name="gender" type="radio" value="M" checked="checked"/><label for="gender1"></label>
<input id="gender2" name="gender" type="radio" value="F"/><label for="gender2"></label>

单选按钮(多选)

<form:radiobuttons />

使用 <form:radiobuttons path="favoriteNumber" items="${numbersList}" /> 标签来渲染一个 HTML 多项单选按钮,等同于:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<span>
<input id="favoriteNumber1" name="favoriteNumber" type="radio" value="1"/>
<label for="favoriteNumber1">1</label>
</span>
<span>
<input id="favoriteNumber2" name="favoriteNumber" type="radio" value="2"/>
<label for="favoriteNumber2">2</label>
</span>
<span>
<input id="favoriteNumber3" name="favoriteNumber" type="radio" value="3"/>
<label for="favoriteNumber3">3</label>
</span>
<span>
<input id="favoriteNumber4" name="favoriteNumber" type="radio" value="4"/>
<label for="favoriteNumber4">4</label>
</span>

下拉列表

使用 <form:select />, <form:option /><form:options /> 标签来渲染一个 HTML 下拉列表,等同于:

1
2
3
4
<form:select path="country">
<form:option value="NONE" label="Select"/>
<form:options items="${countryList}" />
</form:select>
1
2
3
4
5
6
7
<select id="country" name="country">
<option value="NONE">请选择...</option>
<option value="US">United States</option>
<option value="CH">China</option>
<option value="MY">Malaysia</option>
<option value="SG">Singapore</option>
</select>

下拉列表(多选)

使用 <form:select /> 标签及其属性 multiple=true 来渲染一个 HTML 多选下拉列表,等同于:

1
<form:select path="skills" items="${skillsList}" multiple="true" />
1
2
3
4
5
6
7
<select id="skills" name="skills" multiple="multiple">
<option value="Struts">Struts</option>
<option value="Hibernate">Hibernate</option>
<option value="Apache Wicket">Apache Hadoop</option>
<option value="Spring">Spring</option>
</select>
<input type="hidden" name="_skills" value="1"/>

隐藏字段域

<form:hidden />

使用 <form:hidden path="id" value="1000"/> 标签来渲染一个 HTML 隐藏字段域,等同于:

1
<input id="id" name="id" type="hidden" value="1000"/>

Spring MVC 注解

controller

1
2
3
map & pojo 需要加@RequestBody
基本类型 & 数组 & MultipartFile 只要保持页面的参数名称和controller方法形参一致i,就不用加@ReqeustParam
List不管名字一不一样,必须加@RequestParam

dao/mapper

1
2
3
4
map & pojo 不需要加@Param
多参数建议加@Param,不加就需要按照param1,param2 ... paramN
List & Array可以不加@Param,如果不加@aram取值需要写list & array
如果有多个List参数,那么取值,param1 param2 .. paramN

@ModelAttribute

为什么用它?

如果不用它,我们就得一个个手动绑定属性到对象上,然后返回给前端界面。用了它,我们可以在访问请求方法前,执行该注解的方法,拿到对象,赋给界面。相当于前置方法。AOP切面编程思想。

简介

@ModelAttribute 具有如下三个作用:

  • 绑定请求参数到命令对象:放在功能处理方法的入参上时,用于将多个请求参数绑定到一个命令对象,从而简化绑定流程,而且自动暴露为模型数据用于视图页面展示时使用
  • 暴露 @RequestMapping 方法返回值为模型数据:放在功能处理方法的返回值上时,是暴露功能处理方法的返回值为模型数据,用于视图页面展示时使用
  • 暴露表单引用对象为模型数据:放在处理器的一般方法(非功能处理方法)上时,是为表单准备要展示的表单引用对象,如注册时需要选择的所在城市等,而且在执行功能处理方法(@RequestMapping 注解的方法)之前,自动添加到模型对象中,用于视图页面展示时使用

例子

暴露表单引用对象为模型数据的例子

image-20220716123638609

1
2
3
4
5
6
7
8
9
10
11
@ModelAttribute
public User get(@RequestParam(required = false) String id) {
User entity = null;
if (StringUtils.isNotBlank(id)) {
entity = userService.get(id);
}
if (entity == null) {
entity = new User();
}
return entity;
}

要和前端代码配合使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<form:form cssClass="form-horizontal" action="/user/save" method="post" commandName="tbUser">
<div class="box-body">
<div class="form-group">
<label for="email" class="col-sm-2 control-label">邮箱</label>
<div class="col-sm-10">
<form:input path="email" class="form-control" placeholder="请输入邮箱"/>
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-2 control-label">密码</label>
<div class="col-sm-10">
<form:input path="password" class="form-control" placeholder="请输入密码"/>
</div>
</div>
<div class="form-group">
<label for="username" class="col-sm-2 control-label">姓名</label>
<div class="col-sm-10">
<form:input path="username" class="form-control" placeholder="请输入姓名"/>
</div>
</div>
<div class="form-group">
<label for="phone" class="col-sm-2 control-label">手机号</label>
<div class="col-sm-10">
<form:input path="phone" class="form-control" placeholder="请输入手机号"/>
</div>
</div>
</div>
<div class="box-footer">
<button type="button" onclick="history.go(-1)" class="btn btn-default">返回</button>
<button type="submit" class="btn btn-info pull-right">保存</button>
</div>
</form:form>

@ResponseBody

为什么用它?

因为不想让controller的方法返回被视图解析器解析做页面跳转.而且要返回json格式给页面.

简介

@ResponseBody 注解表示该方法的返回的结果直接写入 HTTP 响应正文(ResponseBody)中,一般在异步获取数据时使用,通常是在使用 @RequestMapping 后,返回值通常解析为跳转路径,加上 @ResponseBody 后返回结果不会被解析为跳转路径,而是直接写入HTTP 响应正文中。

作用

该注解用于将 Controller 的方法返回的对象,通过适当的 HttpMessageConverter 转换为指定格式后,写入到 Response 对象的 body 数据区。

使用时机

返回的数据不是 html 标签的页面,而是其他某种格式的数据时(如json、xml等)使用

处理自定义类型

如果需要返回自定义对象为 JSON 数据类型,需要增加 jackson 依赖,pom.xml 配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- Json Begin -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- Json End -->

【2019-07-07注:】为什么不用fastjson(alibaba),因为fastjson的代码很多地方写死了,且代码有bug,而且,有的是模仿jackson的.没有jackson优雅.jackson是目前全球效率最高的.

Spring MVC 实现文件上传

文件上传介绍

文件上传概述以及使用场景

就是把客户端(浏览器)的文件保存一份到服务器 说白了就是文件的拷贝

常见的使用场景:上传头像、上传各种照片、上传word、Excel等等文件

文件上传要求

浏览器端要求(通用浏览器的要求)

  • 表单提交方式 post
  • 提供文件上传框(组件) input type=”file”
  • 表单的entype属性必须为 multipart/form-data(没有这个属性值的话, 文件的内容是提交不过去的)

服务器端要求

  1. 获取客户端上传的文件

  2. 准备一个目录存储客户端上传的文件

  3. 将客户端上传的文件写入到准备好的目录中

注意:

  • 若表单使用了 multipart/form-data ,使用原生request.getParameter()去获取参数的时候都为null

我们做文件上传一般会借助第三方组件(jar, 框架 SpringMVC)实现文件上传.

常见的文件上传jar包和框架

  • serlvet3.0(原生的文件上传的API)

  • commons-fileupload : apache出品的一款专门处理文件上传的工具包 (我们肯定不会直接使用)

  • struts2(底层封装了:commons-fileupload)

  • SpringMVC(底层封装了:commons-fileupload)

案例-springmvc 传统方式文件上传

使用springmvc 完成传统方式文件上传

步骤

  1. 把commons-fileupload坐标导入进来
  2. 在控制器的方法的形参里面定义和文件相关的变量 MultipartFile
  3. 把文件存到服务器
  4. 配置文件解析器

实现

  • 创建Maven工程,添加依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<dependencies>
<!--文件上传组件的依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!--springmvc的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>

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

<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
  • 创建前端页面
1
2
3
4
5
6
<h1>一,springmvc传统方式文件上传</h1>
<form action="/file/upload" method="post" enctype="multipart/form-data">
图片: <input type="file" name="upload"/><br/>
图片描述:<input type="text" name="pdesc"/>
<input type="submit" value="上传"/>
</form>
  • 控制器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.itheima.controller;

import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
* 包名:com.itheima.controller
* @author Leevi
* 日期2020-11-15 08:58
* 服务器端获取客户端上传的文件:
* 1. 在springmvc的配置文件中配置文件解析器,将字节输入流解析成MultipartFile对象
* 2. 在控制器方法中添加MultipartFile类型的参数
*/
@RestController
@RequestMapping("/file")
public class FileController {
@RequestMapping("/upload")
public String upload(MultipartFile upload, String pdesc, HttpSession session) throws IOException {
System.out.println(pdesc);
InputStream is = null;
FileOutputStream out = null;
try {
ServletContext servletContext = session.getServletContext();
// 在部署的项目路径下准备一个upload目录
String realPath = servletContext.getRealPath("upload");
File file = new File(realPath);
if (!file.exists()) {
file.mkdirs();
}
//获取文件名
String originalFilename = upload.getOriginalFilename();
// 使用文件输出流将客户端上传的文件输出到指定目录
out = new FileOutputStream(new File(file, originalFilename));

//客户端上传文件的输入流
is = upload.getInputStream();

IOUtils.copy(is, out);
return "success";
} catch (Exception e) {
e.printStackTrace();
return "fail";
} finally {
is.close();
out.close();
}
}
}
  • 在springmvc.xml配置文件解析器

    注意:文件上传的解析器id 是固定的,不能起别的名称,否则无法实现请求参数的绑定。(不光是文件,其他字段也将无法绑定)

1
2
3
4
5
<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为 5MB -->
<property name="maxUploadSize" value="5242880"></property>
</bean>

案例-springmvc 跨服务器方式上传

了解使用springmvc 跨服务器方式的文件上传

image-20220627154300435

image-20220627154303785

image-20220627154327955

分服务器的目的

在实际开发中,我们会有很多处理不同功能的服务器(注意:此处说的不是服务器集群)。 例如:

  • 应用服务器:负责部署我们的应用
  • 数据库服务器:运行我们的数据库
  • 缓存和消息服务器:负责处理高并发访问的缓存和消息
  • 文件服务器:负责存储用户上传文件的服务器。

分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。

image-20230922140800936

跨服务器方式的文件上传图解

image-20230922140821364

  • 准备两个服务器(默认情况下,tomcat是不允许其他服务器往它里面写入数据的), 修改tomcat的的conf目录下的web.xml, 添加readonly参数为false

image-20230922140832230

实现

  • 添jersey依赖 (跨服务器上传图片的代码)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<dependencies>
<!--引入文件上传的依赖-->
<!--文件上传组件的依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!--springmvc的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>

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

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

<!--跨服务器上传的文件的依赖-->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
</dependencies>
  • 前端页面
1
2
3
4
5
6
<h1>二,springmvc 跨服务器方式的文件上传</h1>
<form action="/file/upload" method="post" enctype="multipart/form-data">
图片: <input type="file" name="upload"/><br/>
图片描述:<input type="text" name="pdesc"/>
<input type="submit" value="上传"/>
</form>
  • 控制器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.itheima.controller;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

/**
* 包名:com.itheima.controller
* @author Leevi
* 日期2020-11-15 08:58
* 跨服务器文件上传:
* 1. 使用springmvc的方式获取客户端上传的文件
* 2. 使用跨服务器上传文件的API,将图片上传到文件服务器
*/
@RestController
@RequestMapping("/file")
public class FileController {

/**
* 改成跨服务器文件上传
* @param upload
* @param pdesc
* @return
* @throws IOException
*/
@RequestMapping("/upload")
public String upload(MultipartFile upload, String pdesc) throws IOException {
System.out.println(pdesc);
try {
//获取文件名
String originalFilename = upload.getOriginalFilename();
//上传文件的路径
String uploadPath = "http://localhost:8899/upload/"+originalFilename;

//创建一个文件上传的客户端
Client client = Client.create();
//建立与服务器的连接
WebResource resource = client.resource(uploadPath);
//将文件上传给服务器
resource.put(upload.getBytes());
return "success";
} catch (Exception e) {
e.printStackTrace();
return "fail";
}
}
}

Spring MVC 中的异常处理

分析

系统中异常包括两类:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。

系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:

image-20230922140846082

springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。

代码实现

自定义异常处理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.itheima.handler;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* 包名:com.itheima.handler
* @author Leevi
* 日期2020-11-15 10:17
* 全局异常处理器:
* 作用: 处理整个项目中所有的controller抛出的异常
* 步骤: 1. 编写一个类实现HandlerExceptionResolver接口
* 2. 重写resolveException方法
* 3. 在springmvc的配置文件中,配置异常解析器
*/
public class GlobalExceptionHandler implements HandlerExceptionResolver {

@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//ex表示这次的异常信息,使用它可以收集异常信息
ex.printStackTrace();//这句代码仅仅是在控制台打印文件

//返回ModelAndView对象就必然要走视图解析器
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
return modelAndView;
}
}

配置异常处理器

  • 在springmvc.xml配置
1
<bean id="sysExceptionResolver" class="com.itheima.handler.GlobalExceptionHandler"></bean>

Spring MVC 中的拦截器

拦截器概述

​ Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器(自己编写的Controller)进行预处理和后处理。

​ 用户可以自己定义一些拦截器来实现特定的功能。谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但是也有区别,接下来我们就来说说他们的区别:

类别 使用范围 拦截范围
拦截器 SpringMVC项目 只会拦截访问的控制器方法的请求
过滤器 任何web项目 任何资源(servlet,控制器,jsp,html等)

​ 我们要想自定义拦截器, 要求必须实现: HandlerInterceptor 接口。

常见应用场景

  • 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等
  • 权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面
  • 性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间
  • 通用行为:读取 Cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现

自定义拦截器入门

  • 编写一个普通类实现 HandlerInterceptor 接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.itheima.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* 包名:com.itheima.interceptor
* @author Leevi
* 日期2020-11-15 10:47
* 拦截器:
* 作用: 在执行controller的方法之前做预处理,以及执行controller的方法之后做后处理
* 步骤:
* 1. 写一个类实现HandlerInterceptor接口
* 2. 选择实现其中的方法:
* 1. preHandle() 在处理器方法之前执行
* 2. postHandle() 在处理器方法之后、视图渲染之前执行
* 3. afterCompletion() 在视图渲染之后执行,官方建议可以在该方法中做一些资源清理操作
* 3. 在springmvc配置文件中进行拦截器的配置(配置拦截器的拦截路径)
*/
public class PermissionInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

System.out.println("PermissionInterceptor的preHandle方法执行了...");
//返回值为true就是放行
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("PermissionInterceptor的postHandle方法执行了...");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("PermissionInterceptor的afterCompletion方法执行了...");
}
}
  • 在springmvc.xml配置拦截器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.itheima"/>

<!--配置拦截器-->
<mvc:interceptors>
<!--里面可以配置多个拦截器,每一个interceptor就是一个拦截器-->
<mvc:interceptor>
<!--mapping表示这个拦截器的拦截范围-->
<mvc:mapping path="/**" />
<!--exclude-mapping-->
<mvc:exclude-mapping path="/hello/sayHaha.do"/>
<!--bean标签表示对我们要进行配置的拦截器做IOC-->
<bean id="permissionInterceptor" class="com.itheima.interceptor.PermissionInterceptor"> </bean>
</mvc:interceptor>
</mvc:interceptors>
</beans>

自定义拦截器进阶

拦截器的放行

image-20230922140859103

拦截器的路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.itheima"/>

<!--配置拦截器-->
<mvc:interceptors>
<!-- 里面可以配置多个拦截器,每一个interceptor就是一个拦截器 -->
<mvc:interceptor>
<!-- mapping表示这个拦截器的拦截范围 /**表示拦截所有控制器方法 -->
<mvc:mapping path="/**" />
<!-- exclude-mapping -->
<mvc:exclude-mapping path="/hello/sayHaha.do"/>
<!-- bean标签表示对我们要进行配置的拦截器做IOC -->
<bean id="permissionInterceptor" class="com.itheima.interceptor.PermissionInterceptor"> </bean>
</mvc:interceptor>
</mvc:interceptors>
</beans>

拦截器的其它方法

  • afterCompletion  在目标方法完成视图层渲染后执行。
  • postHandle  在目标方法执行完毕获得了返回值后执行。
  • preHandle 被拦截的目标方法执行之前执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.itheima.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* 包名:com.itheima.interceptor
* @author Leevi
* 日期2020-11-15 10:47
* 拦截器:
* 作用: 在执行controller的方法之前做预处理,以及执行controller的方法之后做后处理
* 步骤:
* 1. 写一个类实现HandlerInterceptor接口
* 2. 选择实现其中的方法:
* 1. preHandle() 在处理器方法之前执行
* 2. postHandle() 在处理器方法之后、视图渲染之前执行
* 3. afterCompletion() 在视图渲染之后执行,官方建议可以在该方法中做一些资源清理操作
* 3. 在springmvc配置文件中进行拦截器的配置(配置拦截器的拦截路径)
*/
public class PermissionInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

System.out.println("PermissionInterceptor的preHandle方法执行了...");
//返回值为true就是放行
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("PermissionInterceptor的postHandle方法执行了...");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("PermissionInterceptor的afterCompletion方法执行了...");
}
}

多个拦截器执行顺序

回想多个过滤器的执行顺序:

  1. 如果采用配置文件方式配置过滤器,那么就按照过滤器的配置先后顺序执行
  2. 如果采用注解方式配置过滤器,那么就按照类名的排序执行

我们可以配置多个拦截器, 所以就存在一个优先级问题了.多个拦截器的优先级是按照配置的顺序决定的。

image-20230922140910778

配置顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--配置拦截器-->
<mvc:interceptors>
<!--里面可以配置多个拦截器,每一个interceptor就是一个拦截器-->
<mvc:interceptor>
<!--mapping表示这个拦截器的拦截范围-->
<mvc:mapping path="/**" />
<!--exclude-mapping -->
<mvc:exclude-mapping path="/hello/sayHaha.do"/>
<!--bean标签表示对我们要进行配置的拦截器做IOC -->
<bean id="permissionInterceptor" class="com.itheima.interceptor.PermissionInterceptor"> </bean>
</mvc:interceptor>

<mvc:interceptor>
<!--mapping表示这个拦截器的拦截范围 -->
<mvc:mapping path="/**" />
<!--bean标签表示对我们要进行配置的拦截器做IOC -->
<bean id="secondInterceptor" class="com.itheima.interceptor.SecondInterceptor"> </bean>
</mvc:interceptor>
</mvc:interceptors>

将Spring项目改成SSM

第一步-引入依赖

  1. 并且去掉heima_mvc的依赖,并且删除web.xml中相关配置,并且删除掉自己项目中的解决乱码的过滤器
  2. spring相关依赖
    1. spring-webmvc
    2. spring-jdbc
    3. aop依赖
  3. mybatis整合spring的依赖
  4. log相关依赖
  5. jackson相关的依赖
  6. druid连接池依赖
  7. 文件上传的依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<properties> 
<spring.version>5.0.2.RELEASE</spring.version>
<!--日志打印框架-->
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</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-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<!--
关键: mybatis整合spring的依赖
-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.5</version>
</dependency>
<!--SpringAOP相关的坐标-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
</dependencies>

第二步-修改mybatis的核心配置文件

第三步-编写spring整合mybatis的配置文件

  1. 整合mybatis

第四步-编写声明式事务的配置文件

  1. 配置事务管理者
  2. 加载事务注解驱动
  3. 导入spring-mybatis.xml

第五步-编写spring的主配置文件

  1. 包扫描
  2. 加载mvc注解驱动
  3. 导入导入spring-tx.xml

第六步-修改web.xml配置

  1. 将heimaMVC中的DispatcherServlet的配置改成SpringMVC中的DispatcherServlet的配置
  2. 将解决乱码的过滤器的配置改成SpringMVC中的解决乱码的过滤器配置
  3. 删除项目中自己定义的解决乱码的过滤器

第七步-修改各个controller的代码

  1. 将原本heimaMvc的Controller注解改成springMvc中的RestController注解
  2. 使用Autowired注解注入Service对象
  3. 在各个Controller类上添加RequestMapping注解
  4. 将Controller类的各个方法上的RequestMapping注解改成SpringMVC中的RequestMapping注解,并且修改路径
  5. 将各个方法的获取请求参数的方式改成SpringMVC中的获取请求参数
  6. 将各个方法的响应数据给客户端的方式改成SpringMVC的响应数据方式

第八步-修改各个Service的代码

  1. 将所有的Service的实现类改名成”XXXImpl”
  2. 给各个实现类添加接口,然后Controller中一定要以接口类型接收Service的对象
  3. 各个Service的实现类商添加Service注解进行IOC
  4. 使用Autowired注解注入Dao对象
  5. 将方法中所有涉及到SqlSession的代码全部删掉,直接就能使用Dao对象
  6. 要进行事务控制的类或者方法上添加Transactional注解

第九步-修改文件上传的代码

  1. 将原来的获取上传文件的代码改成SpringMVC的文件上传代码
  2. 在创建spring文件上传的配置文件,配置文件解析器

SSM总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
一、MyBatis框架
1. 映射配置文件
1. 映射配置文件的文件名和存储路径,要和对应的Dao接口的名字和路径一致
2. mapper根标签,namespace属性的值,要和对应的Dao接口的全限定名一致
3. insert、delete、update、select、selectKey标签
4. parameterType 参数类型
5. resultType 结果类型
6. resultMap 自定义结果集映射
7. 动态SQL标签
if
where
forEach
sql和include标签
8. 一对一的映射、一对多的映射

二、Spring框架
1. 掌握注解的方式进行:IOC(控制反转)和DI(依赖注入),配置文件方式也要掌握
1.1 自己写的类,使用注解方式进行IOC和DI
1.2 第三方的类,使用配置文件方式进行IOC和DI

2. 配置文件方式使用AOP、注解的方式使用AOP

3. 注解的方式使用声明式事务

4. 配置DataSource

三、SpringMVC框架
1. 配置前端控制器(DispatcherServlet)
2. 配置解决乱码的过滤器
3. 常用注解
Controller注解
RestController注解
RequestMapping注解
RequestParam注解
RequestBody注解

4. 与json数据的交互(项目中必须引入jackson依赖)
1. 接收客户端的json类型的请求参数,封装到POJO对象中,使用RequestBody注解
2. 将服务器端的对象,解析成json字符串,响应给客户端,可以使用ResponseBody注解,也可以使用RestController

5. 获取客户端的请求参数
1. 简单类型的参数
2. POJO对象类型的参数
1. "key=value&key=value"
2. "{key:value,key:value}"

3. Map类型的参数
4. List类型的参数

6. 使用PathVariable注解获取RestFul风格的url中的数据

7. 掌握文件上传

四、掌握使用spring整合mybatis
1. 引入整合的依赖
2. 在spring-mybatis.xml里面配置SqlSessionFactoryBean对象,注入DataSource,typeAliasesPackage
3. 配置MapperScannerConfigurer对象,注入要加载的dao接口的包名

五、能够让专门的配置文件做专门的事情:
1. springmvc的配置文件:项目全局的配置文件
1. 包扫描
2. 加载mvc注解驱动
3. 配置springmvc的各种组件:视图解析器、文件解析器、异常处理器、类型转换器、拦截器等等
4. 导入其它的配置文件

2. spring的配置文件:
1. aop的配置
2. 声明式事务的配置
3. 其它的一些ioc和依赖注入的配置
4. 导入其它的配置文件(如果有需要的话)

3. spring-mybatis.xml,做整合的事情
1. 配置dataSource
2. 整合mybatis和spring

4. log4j.properties 日志框架的配置文件

5. db.properties 数据库环境的配置文件

6. web.xml,里面是配置Servlet和Filter、Listener

7. mybatis的主配置文件、mybatis的映射配置文件

附录

web.xml

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>Archetype Created Web Application</display-name>

</web-app>

springmvc.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

</beans>

applicationContext(约束).xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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:aop="http://www.springframework.org/schema/aop"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">




</beans>

sqlMapConfig.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 指定读取的properties文件,同级目录直接写文件名 -->
<properties resource="jdbcConfig.properties"></properties>
<!-- 配置mybatis的环境,default表示默认使用哪个id -->
<environments default="mysql">
<!-- 配置环境,id是环境的唯一标识 -->
<environment id="mysql">
<!-- 配置使用的事务 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置连接池 -->
<dataSource type="pooled">
<!-- 配置创建连接池的必要信息 value可以使用表达式获取properties文件中的内容 -->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>

<!-- 配置映射文件的位置,或者注解类的位置 -->
<mappers>
<!-- 基于XML的配置方式:<mapper resource="com/itheima/dao/IAccountDao.xml"/> -->
<!-- 基于注解的配置方式 -->
<mapper class="com.itheima.dao.IAccountDao"/>
</mappers>
</configuration>