SpringMVC简介

MVC模型

MVC全称Model View Controller,是一种设计创建Web应用程序的模式。这三个单词分别代表Web应用的三个部分:

Model(模型):指数据模型。用于存储数据以及处理用户请求的业务逻辑。在Web应用中,JavaBean对象、业务模型等都属于Model。

View(视图):用于展示模型中的数据的,一般为jsp或html文件

Controller(控制器):是应用程序中处理用户交互的部分,接受视图提出的请求,将数据交给模型处理,并将处理后的结果交给视图显示。

image-20211214152348721

SpringMVC

SpringMVC是一个基于MVC模式的轻量级Web框架,是Spring框架的一个模块,和Spring可以直接整合使用。SpringMVC代替了Servlet技术,它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。

(SpringMVC代替了S)

SpringMVC入门案例

image-20220416121847360

接下来我们编写一个SpringMVC的入门案例

1.引入maven创建web项目,补齐包结构

2.引入相关依赖和tomcat插件

<?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.itbaizhan</groupId>
<artifactId>mvc_demo1</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

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

<dependencies>
<!-- Spring核心模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<!-- SpringWeb模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<!-- SpringMVC模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- JSP -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<!-- tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8080</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
<server>tomcat7</server>
<systemProperties>
<java.util.logging.SimpleFormatter.format>%1$tH:%1$tM:%1$tS %2$s%n%4$s: %5$s%6$s%n
</java.util.logging.SimpleFormatter.format>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
</project>

3.在web.xml中配置前端控制器DispathcerServlet

<!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>
<!--SpringMVC前端控制器,本质是一个Servlet,接收所有请求,在容器启动时就会加载-->
<servlet>
<servlet-name>dispatcherServlet</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>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

4.编写SpringMVC核心配置文件springmvc.xml,该文件和Spring配置文件写法一样

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

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

<!-- 开启SpringMVC注解的支持 -->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>

5.编写控制器

package com.itbaizhan.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController1 {
// 该方法的访问路径是/c1/hello1
@RequestMapping("/c1/hello1")
public void helloMVC()
{
System.out.println("hello SpringMVC!");
}
}

使用tomcat插件启动项目,访问 http://localhost:8080/c1/hello1

使用SpringMVC必须要配置的是前端控制器

SpringMVC执行流程

image-20211222093922306

SpringMVC的组件:

  • DispatcherServlet:前端控制器,接受所有请求,调用其他组件。
  • HandlerMapping:处理器映射器,根据配置找到方法的执行链。
  • HandlerAdapter:处理器适配器,根据方法类型找到对应的处理器。
  • ViewResolver:视图解析器,找到指定视图。

组件的工作流程

  1. 客户端将请求发送给前端控制器。
  2. 前端控制器将请求发送给处理器映射器,处理器映射器根据路径找到方法的执行链,返回给前端控制器。
  3. 前端控制器将方法的执行链发送给处理器适配器,处理器适配器根据方法类型找到对应的处理器。
  4. 处理器执行方法,将结果返回给前端控制器。
  5. 前端控制器将结果发送给视图解析器,视图解析器找到视图文件位置。
  6. 视图渲染数据并将结果显示到客户端

SpringMVC参数获取_封装为简单数据类型

image-20211221144403791

在Servlet中我们通过request.getParameter(name)获取请求参数。该方式存在两个问题:

  • 请求参数较多时会出现代码冗余。
  • 与容器紧耦合。

而SpringMVC支持参数注入的方式用于获取请求数据,即将请求参数直接封装到方法的参数当中。用法如下:

1.编写控制器方法

//获取简单类型参数
@RequestMapping("/c1/param1")
public void simpleParam(String username,int age)
{
System.out.println(username);
System.out.println(age);
}

访问该方法时,请求参数名和方法参数名相同,即可完成自动封装。

http://localhost:8080/c1/param1?username=bz&age=10

在SpringMVC中,接受简单类型参数时,请求参数名和方法参数名相同即可自动封装

SpringMVC参数获取_封装为对象类型

image-20211221144613779

SpringMVC支持将参数直接封装为对象,写法如下:

封装单个对象

1.编写实体类

package com.itbaizhan.domain;

public class Student {
private int id;
private String name;
private String sex;

@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

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

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}
}

2.编写控制器方法

//获取对象类型参数
@RequestMapping("/c1/param2")
public void objParam(Student student)
{
System.out.println(student);
}

3.访问该方法时,请求参数名和方法参数的属性名相同,即可完成自动封装。

http://localhost:8080/c1/param2?id=1&name=bz&sex=female

封装关联对象

1.编写实体类

package com.itbaizhan.domain;

public class Address {
private String info;
private String psotcode;

@Override
public String toString() {
return "Address{" +
"info='" + info + '\'' +
", psotcode='" + psotcode + '\'' +
'}';
}

public String getInfo() {
return info;
}

public void setInfo(String info) {
this.info = info;
}

public String getPsotcode() {
return psotcode;
}

public void setPsotcode(String psotcode) {
this.psotcode = psotcode;
}
}
package com.itbaizhan.domain;

public class Student {
private int id;
private String name;
private String sex;
private Address address;

@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", address=" + address +
'}';
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

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

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public Address getAddress() {
return address;
}

public void setAddress(Address address) {
this.address = address;
}
}

2.编写控制器方法

//获取关联对象类型参数
@RequestMapping("/c1/param3")
public void objParam2(Student student)
{
System.out.println(student);
}

3.访问该方法时,请求参数名和方法参数的属性名相同,即可完成自动封装。

http://localhost:8080/c1/param3?id=1&name=bz&sex=female&address.info=beijing&address.postcode=030000

4.我们也可以使用表单发送带有参数的请求(直接访问jsp):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>表单提交</title>
</head>
<body>
<form action="/c1/param3" method="post">
id:<input name="id">
姓名:<input name="name">
性别:<input name="sex">
地址:<input name="address.info">
邮编:<input name="address.postcode">
<input type="submit">
</form>
</body>
</html>

SpringMVC参数获取_封装为集合类型

SpringMVC支持将参数封装为List或Map集合,写法如下:

封装为List集合

封装为简单数据类型集合

1.编写控制器方法

// 绑定简单数据类型List参数,参数前必须添加@RequestParam注解
@RequestMapping("/c1/param4")
public void listParam(@RequestParam List<String> users)
{
System.out.println(users);
}

该方法也可以绑定数组类型:

//绑定数组在参数前也必须添加@RequestParam注解
@RequestMapping("/c1/param5")
public void listParam2(@RequestParam String[] users){
System.out.println(users[0]);
System.out.println(users[1]);
}

2.请求的参数写法

http://localhost:8080/c1/param4?users=bj&users=sxt

封装为对象类型集合

SpringMVC不支持将参数封装为对象类型的List集合,但可以封装到有List属性的对象中

1.编写实体类

package com.itbaizhan.domain;

import java.util.List;

public class Student {
private int id;
private String name;
private String sex;
private Address address;//地址对象
private List<Address> addres;//地址集合

@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", address=" + address +
", addres=" + addres +
'}';
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

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

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public Address getAddress() {
return address;
}

public void setAddress(Address address) {
this.address = address;
}

public List<Address> getAddres() {
return addres;
}

public void setAddres(List<Address> addres) {
this.addres = addres;
}
}

2编写控制器方法

//对象中包含集合属性
@RequestMapping("/c1/param6")
public void listParam3(Student student)
{
System.out.println(student);
}

3.请求的参数写法

http://localhost:8080/c1/param6?id=1&name=bz&sex=female&address[0\].info=bj&address[0].postcode=100010&address[1].info=sh&address[1].postcode=100011](http://localhost:8080/c1/param5?id=1&name=bz&sex=female&address[0].info=bj&address[0].postcode=100010&address[1].info=sh&address[1].postcode=100011)

封装为Map集合

同样,SpringMVC要封装Map集合,需要封装到有Map属性的对象中

1.编写实体类

package com.itbaizhan.domain;

import java.util.List;
import java.util.Map;

public class Student {
private int id;
private String name;
private String sex;
// private Address address;//地址对象
// private List<Address> addres;//地址集合
private Map<String,Address> address;

@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", address=" + address +
'}';
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

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

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public Map<String, Address> getAddress() {
return address;
}

public void setAddress(Map<String, Address> address) {
this.address = address;
}
}

2.编写控制器方法

//对象中包含Map属性
@RequestMapping("/c1/param7")
public void mapParam(Student student)
{
System.out.println(student);
}

3.请求的参数写法

http://localhost:8080/c1/param7?id=1&name=bz&sex=female&address[‘one’\].info=bj&address[‘one’].postcode=100010&address[‘two’].info=sh&address[‘two’].postcode=100011]

SpringMVC参数获取_使用Servlet原生对象获取参数、

image-20211221150011327

SpringMVC也支持使用Servlet原生对象,在方法参数中定义HttpServletRequestHttpServletResponseHttpSession等类型的参数即可直接在方法中使用。

//使用servlet原生对象
@RequestMapping("/c1/param8")
public void servletParam(HttpServletRequest request, HttpServletResponse response, HttpSession session)
{
//原生对象获取参数
System.out.println(request.getParameter("name"));
System.out.println(response.getCharacterEncoding());
System.out.println(session.getId());
}

访问该方法即可:http://localhost:8080/c1/param8?name=bjsxt

一般情况下,在SpringMVC中都有对Servlet原生对象的方法的替代,推荐使用SpringMVC的方式代替Servlet原生对象。

SpringMVC参数获取_自定义参数类型转换器

image-20211221150206521

前端传来的参数全部为字符串类型,SpringMVC使用自带的转换器将字符串参数转为需要的类型。如:

// 获取简单类型参数
@RequestMapping("/c1/param1")
public void simpleParam(String username,int age){
System.out.println(username);
System.out.println(age);
}

请求路径:http://localhost:8080/c1/param1?username=bz&age=10

但在某些情况下,无法将字符串转为需要的类型,如:

@RequestMapping("/c1/param9")
public void dateParam(Date birthday){
System.out.println(birthday);
}

由于日期数据有很多种格式,SpringMVC没办法把所有格式的字符串转换成日期类型。比如参数格式为birthday=2025-01-01时,SpringMVC就无法解析参数。此时需要自定义参数类型转换器。

1.定义类型转换器类,实现Converter接口

package com.itbaizhan.converter;

import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

// 类型转换器必须实现Converter接口,两个泛型代表转换前的类型,转换后的类型
public class DateConverter implements Converter<String, Date> {

/**
* 转换方法
* @param source 转换前的数据
* @return 转换后的数据
*/

@Override
public Date convert(String source) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = sdf.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}

2.注册类型转换器对象

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

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

<!-- 开启SpringMVC注解的支持 -->
<mvc:annotation-driven conversion-service="dateConverter"></mvc:annotation-driven>

<!-- 配置转换器工厂 -->
<bean id="dateConverter" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!-- 转换器集合 -->
<property name="converters">
<set>
<!-- 自定义转换器 -->
<bean class="com.itbaizhan.converter.DateConverter"></bean>
</set>
</property>
</bean>
</beans>

3.此时再访问http://localhost:8080/c1/param9?birthday=2025-01-01时,SpringMVC即可将请求参数封装为Date类型的参数。

SpringMVC参数获取_编码过滤器

image-20211221151108190

在传递参数时,tomcat8以上能处理get请求的中文乱码,但不能处理post请求的中文乱码

1.编写jsp表单

<%--
Created by IntelliJ IDEA.
User: 百里诀
Date: 2022/4/18
Time: 22:35
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>编码过滤器</title>
</head>
<body>
<form action="/cn/code" method="post">
姓名:<input name="username">
<input type="submit">
</form>
</body>
</html>

2.编写控制器方法

@RequestMapping("/cn/code")
public void code(String username){
System.out.println(username);
}

SpringMVC提供了处理中文乱码的过滤器,在web.xml中配置该过滤器即可解决中文乱码问题:

3.web.xml配置文件加上过滤器

<!--SpringMVC中提供的字符编码过滤器,放在所有过滤器的最上方-->
<filter>
<filter-name>encFilter</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>
</filter>
<filter-mapping>
<filter-name>encFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

SpringMVC处理相应_配置视图解析器

image-20211221151231598

SpringMVC默认情况下会在控制器执行完成后跳转到视图页面,视图解析器能找到相应的视图,之前的404异常就是由于没有配置视图解析器导致找不到视图。

在SpringMVC中提供了13个视图解析器,用于支持不同的视图技术。InternalResourceViewResolver是SpringMVC的默认视图解析器,用来解析JSP视图。

<!-- 视图解析器  -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/"></property>
<!-- 视图后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>

SpringMVC处理响应_控制器方法的返回值

image-20211221151653860

我们可以通过控制器方法的返回值设置跳转的视图,控制器方法支持以下返回值类型:

返回值为void

此时会跳转到名字是 前缀+方法路径名+后缀 的jsp页面

1.编写控制器方法

package com.itbaizhan.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController2 {
// 路径是helloMVC,方法执行完后会跳转到/helloMVC.jsp
@RequestMapping("/helloMVC")
public void helloMVC()
{
System.out.println("hello SpringMVC");
}
}

2.编写helloMVC.jsp

<%--
Created by IntelliJ IDEA.
User: 百里诀
Date: 2022/4/18
Time: 23:09
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>MVC</title>
</head>
<body>
<h11>欢迎来到MVC</h11>
</body>
</html>

SpringMVC控制器方法返回值为void表示跳转到方法路径名的视图

返回值为String

此时会跳转到名字是前缀+返回值+后缀的jsp页面

编写控制器方法

//返回值为String
@RequestMapping("c2/hello1")
public String helloMVC1()
{
System.out.println("hello SpringMVC!");
//方法执行完后会跳转到/helloMVC.jsp
return "helloMVC";
}

SpringMVC控制器方法返回值为String类型表示跳转到方法返回值的视图

返回值为ModelAndView

这是SpringMVC提供的对象,该对象可以向request域设置数据并指定跳转的页面。该对象中包含Model对象和View对象。

  • Model:向request域中设置数据。
  • View:指定跳转的页面。

1.编写控制器方法

//返回值为ModelAndView
@RequestMapping("/c2/hello2")
public ModelAndView useMAV()
{
System.out.println("返回值类型为ModelAndView");
// 1.创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
// 2.获取Model对象,本质是一个Map
Map<String, Object> model = modelAndView.getModel();
// 3.使用Model对象向request域设置数据
model.put("name","百战程序员");
// 4.使用View对象设置跳转的路径为/baizhan.jsp
modelAndView.setViewName("baizhan");
return modelAndView;

}

2.编写jsp页面

<%--
Created by IntelliJ IDEA.
User: 百里诀
Date: 2022/4/18
Time: 23:41
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>百战</title>
</head>
<body>
<h1>你好! ${requestScope.name}</h1>
</body>
</html>

SpringMVC处理响应_request域设置数据

image-20211221151953392

当控制器返回值为ModelAndView时我们可以向request域设置数据,我们还有以下方法可以向request域设置数据:

使用原生的HttpServletRequest

@RequestMapping("/c2/hello3")
public String setRequestModel(HttpServletRequest request){
request.setAttribute("username","尚学堂");
return "baizhan";
}

使用Model、ModelMap

SpringMVC提供了Model接口和ModelMap类,控制器方法添加这两个类型的参数,使用该参数设置数据,该数据就会存到request域中。

@RequestMapping("/c2/hello4")
public String setRequestModel2(Model model, ModelMap modelMap){
// 使用Model将数据存入request域
// model.addAttribute("username","尚学堂");
// 使用ModelMap将数据存入request域
modelMap.addAttribute("username","尚学堂");
return "baizhan

使用Map集合

Model接口底层就是一个Map集合,我们可以给控制器方法设置Map类型的参数,向Map中添加键值对,数据也会存到request域中。

@RequestMapping("/c2/hello5")
public String setRequestModel3(Map map){
map.put("username","尚学堂");
return "baizhan";
}

SpringMVC处理响应_session域设置数据

image-20211221152124496

Session作用域表示在当前会话中有效。在SpringMVC中对于Session作用域传值,只能使用HttpSession对象来实现。

1.编写控制器方法

@RequestMapping("/c2/hello6")
public String setSessionModel(HttpSession session)
{
session.setAttribute("address","北京");
return "baizhan";
}

2.编写jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" 
isELIgnored="false" %>
<html>
<head>
<title>百战</title>
</head>
<body>
<h1>你好! ${requestScope.username}</h1>
<h1>地址是! ${sessionScope.address}</h1>
</body>
</html>

SpringMVC处理响应_context域设置数据

context作用域表示在整个应用范围都有效。在SpringMVC中对context作用域传值,只能使用ServletContext对象来实现。但是该对象不能直接注入到方法参数中,需要通过HttpSession对象获取。

1.编写控制器方法

@RequestMapping("/c2/hello7")
public String setContextModel(HttpSession session)
{
ServletContext servletContext = session.getServletContext();
servletContext.setAttribute("age",10);
return "baizhan";
}

2.编写jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java"
isELIgnored="false" %>
<html>
<head>
<title>百战</title>
</head>
<body>
<h1>你好! ${requestScope.username}</h1>
<h1>地址是! ${sessionScope.address}</h1>
<h1>年龄是! ${applicationScope.age}</h1>
</body>
</html>

SpringMVC处理响应_请求转发&重定向

之前的案例,我们发现request域中的值可以传到jsp页面中,也就是通过视图解析器跳转到视图的底层是请求转发。

如果我们跳转时不想使用视图解析器,可以使用原生HttpServletRequest进行请求转发或HttpServletResponse进行重定向:

@RequestMapping("/c2/hello8")
public void myForward1(HttpServletRequest request, HttpServletResponse response) throws Exception{
request.setAttribute("name","尚学堂");
// 请求转发
// request.getRequestDispatcher("/c2/hello9").forward(request,response);
// 原生重定向
response.sendRedirect("/c2/hello9");
}

@RequestMapping("/c2/hello9")
public void myForward2(HttpServletRequest request){
System.out.println("hello");
System.out.println(request.getAttribute("name"));
}

SpringMVC还提供了一种更简单的请求转发和重定向的写法:

@RequestMapping("/c2/hello10")
public String myForward3(HttpServletRequest request)
{
request.setAttribute("name","尚学堂");
//请求转发
return "forward:/c2/hello9";
// 重定向
// return "redirect:/c2/hello9";
}

SpringMVC提供的重定向写法为: return "redirect:视图路径"

SpringMVC提供的请求转发写法为 return “forward:视图路径”

SpringMVC注解_@Controller

作用:标记控制器,将控制器交给Spring容器管理。

位置:类上方

SpringMVC注解_@RequestMapping

作用:给控制器方法设置请求路径

位置:方法或类上方。用于类上,表示类中的所有控制器方法都是以该地址作为父路径

属性:

  • value/path:请求路径
  • method:指定请求方式
  • params:规定必须发送的请求参数
  • headers:规定请求必须包含的请求头
@Controller
@RequestMapping("/c3")
public class MyController3 {

/*
访问路径为 /c3/annotation1
支持post和get请求
请求时必须带有age参数
请求时必须带有User-agent请求头
*/

@RequestMapping(path = "/annotation1",method = {RequestMethod.GET,RequestMethod.POST},params = {"age"},headers = {"User-agent"})
public String annotation1(String username){
System.out.println(username);
return "baizhan";
}
}

SpringMVC注解_@RequestParam

作用:在控制器方法中获取请求参数

位置:方法参数前

属性:

  • name:指定请求参数名称
  • defaultValue: 为参数设置默认值
  • required:设置是否是必须要传入的参数
/*
定义请求的参数名为username,默认值为sxt,不是必须的参数
*/

@RequestMapping("/annotation2")
public String annotation2(@RequestParam(name = "username",defaultValue = "sxt",required = false) String name){
System.out.println(name);
return "baizhan";
}

请求URL的写法:http://localhost:8080/c3/annotation2?username=bz

SpringMVC注解_@RequestHeader、@CookieValue

image-20211221155419568

@RequestHeader

作用:在控制器方法中获取请求头数据

位置:方法参数前

@CookieValue

作用:在控制器方法中获取Cookie数据

位置:方法参数前

/*
获取User-Agent请求头
获取JSESSIONID的Cookie值
*/

@RequestMapping("/annotation3")

public String annotation3(@RequestHeader("User-Agent") String userAgent, @CookieValue("JSESSIONID") String jSessionId){
System.out.println(userAgent);
System.out.println(jSessionId);
return "baizhan";
}

SpringMVC注解_@SessionAttributes

image-20211221155558588

作用:将Model模型中的数据存到session域中

位置:类上方

@Controller
@RequestMapping("/c4")
// 将模型中的name数据保存到session中
@SessionAttributes("name")

public class MyController4 {
@RequestMapping("/t1")
public String t1(Model model){
// model中保存name数据
model.addAttribute("name","北京尚学堂");
return "baizhan";
}


@RequestMapping("/t2")
public String t2(HttpSession session){
// 从session中获取name数据
System.out.println(session.getAttribute("name"));
return "baizhan";
}
}
在SpringMVC中,可以将Model模型中的数据存到session域中@SessionAttributes

SpringMVC注解_@ModelAttribute

image-20211221155843046

作用1:设置指定方法在控制器其他方法前执行

位置:方法上方

@Controller
@RequestMapping("/c5")
public class MyController5 {
@ModelAttribute
public void before(){
System.out.println("前置方法");
}


@RequestMapping("/t1")
public String t1(){
System.out.println("t1");
return "baizhan";

}

}

作用2:从Model模型中获取数据给参数赋值

位置:方法参数前

@Controller
@RequestMapping("/c6")
public class MyController6 {
// 前置方法向Model中设置数据
@ModelAttribute
public void before(Model model){
model.addAttribute("name","尚学堂");
}


// 该参数不是从请求中获取,而是从Model中获取
@RequestMapping("/t1")
public String t1(@ModelAttribute("name") String name){
System.out.println(name);
return "baizhan";
}
}

SpringMVC注解_RESTful风格支持

image-20211221160001230

RESTful风格介绍

RESTful风格是一种URL路径的设计风格。在RESTful风格的URL路径中,网络上的任意数据都可以看成一个资源,它可以是一段文本、一张图片,也可以是一个Java对象。而每个资源都会占据一个网络路径,无论对该资源进行增删改查,访问的路径是一致的。

传统URL:

RESTful风格URL:

那么如何区分对该资源是哪一种操作?通过请求方式不同,判断进行的是什么操作。之前我们学过两种请求方式,GET请求和POST请求,而访问RESTful风格的URL一共有四种请求方式:

  • GET请求:查询操作
  • POST请求:新增操作
  • DELETE请求:删除操作
  • PUT请求:修改操作

RESTful风格URL:

RESTful风格的特点:

结构清晰、符合标准、易于理解、拓展方便

POSTMAN使用

默认情况下浏览器是无法发送DELETE请求和PUT请求的,我们可以使用Postman工具发送这些请求。

  1. 双击安装包安装Postman

  2. 点击new-collection创建请求集合

image-20211215173844221

3.添加请求

image-20211215174251262

4.保存请求到集合,以后可以随时发送该请求

image-20211215174648965

@PathVariable

image-20211221160310362

作用:在RESTful风格的URL中获取占位符的值

位置:方法参数前

属性:

  • value:获取哪个占位符的值作为参数值,如果占位符和参数名相同,可以省略该属性。
package com.itbaizhan.controller;

import com.itbaizhan.domain.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/student")
//模拟学生的增删改查控制器
public class StudentController {
// 路径中的{id}表示占位符,最后会封装到方法的参数中使用

//删除学生
@RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
public String deleteStudent(@PathVariable("id") int id)
{
System.out.println("删除id为"+id+"的学生");
return "baizhan";
}

//新增学生
@RequestMapping(value = "/{id}",method = RequestMethod.POST)
public String addStudent(@PathVariable int id, Student student)
{
System.out.println(id);
System.out.println(student);
System.out.println("新增学生");
return "baizhan";
}

// 如果占位符和参数名相同,可以省略@PathVariable的value属性
//根据id查询学生
@RequestMapping(value = "/{id}",method = RequestMethod.GET)
public String findStudentById(@PathVariable int id)
{
System.out.println(id);
System.out.println("根据id查询学生");
return "baizhan";
}

//修改学生
@RequestMapping(value = "/{id}",method = RequestMethod.PUT)
public String updateStudent(@PathVariable int id, Student student)
{
System.out.println(id);
System.out.println(student);
System.out.println("修改学生");
return "baizhan";
}
}

访问方式:

@PostMapping、@GetMapping、@PutMapping、@DeleteMapping

作用:简化设置请求方式的@RequestMapping写法

位置:方法上方。

package com.itbaizhan.controller;

import com.itbaizhan.domain.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("/student")
//模拟学生的增删改查控制器
public class StudentController {
// 路径中的{id}表示占位符,最后会封装到方法的参数中使用

//删除学生
// @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
@DeleteMapping("/{id}")
public String deleteStudent(@PathVariable("id") int id)
{
System.out.println("删除id为"+id+"的学生");
return "baizhan";
}

//新增学生
// @RequestMapping(value = "/{id}",method = RequestMethod.POST)
@PostMapping("/{id}")
public String addStudent(@PathVariable int id, Student student)
{
System.out.println(id);
System.out.println(student);
System.out.println("新增学生");
return "baizhan";
}

// 如果占位符和参数名相同,可以省略@PathVariable的value属性
//根据id查询学生
// @RequestMapping(value = "/{id}",method = RequestMethod.GET)
@GetMapping("/{id}")
public String findStudentById(@PathVariable int id)
{
System.out.println(id);
System.out.println("根据id查询学生");
return "baizhan";
}

//修改学生
// @RequestMapping(value = "/{id}",method = RequestMethod.PUT)
@PutMapping("/{id}")
public String updateStudent(@PathVariable int id, Student student)
{
System.out.println(id);
System.out.println(student);
System.out.println("修改学生");
return "baizhan";
}
}

HiddentHttpMethodFilter

image-20211221160451965

由于浏览器form表单只支持GET与POST请求,而DELETE、PUT请求并不支持,SpringMVC有一个过滤器,可以将浏览器的POST请求改为指定的请求方式,发送给的控制器方法。

用法如下:

1.在web.xml中配置过滤器

<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>

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

2.编写控制器方法

package com.itbaizhan.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/c7")
public class MyController7
{
@DeleteMapping("/delete")
public String testDelete()
{
System.out.println("删除方法");
return "baizhan";
}

@PutMapping("/put")
public String testPut()
{
System.out.println("修改方法");
return "baizhan";
}
}

3.在jsp中编写表单

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>DELETE、PUT提交</title>
</head>
<body>
<%--删除--%>
<%-- 提交DELETE、PUT请求,表单必须提交方式为post --%>
<form action="/c7/delete" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="删除">
</form>
<hr/>
<%-- 修改 --%>
<form action="/c7/put" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="修改">
</form>
</body>
</html>

SpringMVC注解_@ResponseBody

image-20211221160814897

作用:方法返回的对象转换为JSON格式,并将JSON数据直接写入到输出流中,使用此注解后不会再经过视图解析器。使用该注解可以处理Ajax请求。

位置:方法上方或方法返回值前

1.编写jsp页面,发送ajax请求

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>ajax请求 </title>
<script src="/js/jquery-2.1.1.min.js"></script>
<script>
$(function () {
$("#btn").click(function () {
var name =$("#name").val();
var sex =$("#sex").val();
$.get("/c8/addStudent",{"name":name,"sex":sex},function (data) {
console.log(data);
});
});
});
</script>
</head>
<body>
姓名:<input id="name"/><br/>
性别:<input id="sex"/><br/>
<input type="button" value="提交" id="btn"/>
</body>
</html>

2.由于jsp页面中引入jQuery的js文件,而SpringMVC会拦截所有资源,造成jquery.js失效,需要在SpringMVC核心配置文件中放行静态资源。

<!-- 放行静态资源 -->
<mvc:default-servlet-handler />

3.编写结果实体类,该实体类会封装一个请求的结果

package com.itbaizhan.domain;

//请求的结果对象
public class Result {
private boolean flag;//请求是否成功
private String message;//请求提示信息

public Result() {
}

public Result(boolean flag, String message) {
this.flag = flag;
this.message = message;
}

@Override
public String toString() {
return "Result{" +
"flag=" + flag +
", message='" + message + '\'' +
'}';
}

public boolean isFlag() {
return flag;
}

public void setFlag(boolean flag) {
this.flag = flag;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}
}

4.编写控制器

package com.itbaizhan.controller;

import com.itbaizhan.domain.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/c8")
public class MyController8 {
@PostMapping("/addStudent")
@ResponseBody
public Result addStudent(String name,String sex)
{
// 输出接受到的参数,模拟添加学生
System.out.println(name+":"+sex);
// 返回添加结果
Result result = new Result(true, "添加学生成功!");
return result;
}
}
5.SpringMVC会将Result对象转为JSON格式写入输出流,而SpringMVC默认使用的JSON转换器是jackson,需要在pom中添加jackson依赖
<!-- jackson -->
<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>

SpringMVC注解_@RestController

如果一个控制器类下的所有控制器方法都返回JSON格式数据且不进行跳转,可以使用@RestController代替@Controller,此时每个方法上的@ResonseBody都可以省略

//@Controller
@RestController
@RequestMapping("/c8")
public class MyController8 {
@PostMapping("/addStudent")
// @ResponseBody
public Result addStudent(String name,String sex)
{
// 输出接受到的参数,模拟添加学生
System.out.println(name+":"+sex);
// 返回添加结果
Result result = new Result(true, "添加学生成功!");
return result;
}
}

静态资源映射

image-20211221160948500

当在DispatcherServlet的中配置拦截”/“时,除了jsp文件不会拦截以外,其他所有的请求都会经过前端控制器进行匹配。此时静态资源例如css、js、jpg等就会被前端控制器拦截,导致不能访问,出现404问题。想要正常映射静态资源共有三种方案:

配置静态资源筛查器

在SpringMVC的配置文件中配置<mvc:default-servlet-handler />后,会在Spring容器中创建一个资源检查器,它对进入DispatcherServlet的URL进行筛查,如果不是静态资源,才由DispatcherServlet处理。

修改SpringMVC核心配置文件:

<mvc:default-servlet-handler/>

配置静态资源映射器

SpringMVC模块提供了静态资源映射器组件,通过<mvc:resources>标签配置静态资源映射器,配置后的路径不会由DispatcherServlet处理。

修改SpringMVC核心配置文件:

<!--配置静态资源映射器-->
<!-- mapping:配置请求的URL location:资源路径-->
<mvc:resources mapping="/img/" location="/img/"/><mvc:resources mapping="/js/" location="/js/"/>

配置默认Servlet处理静态资源

在web.xml可以配置默认Servlet处理静态资源,该Servlet由tomcat提供,它会直接访问静态资源不进行其他操作。这样就避免了使用DispatcherServlet对静态资源的拦截:

修改web.xml:

<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</url-pattern>
</servlet-mapping>

SpringMVC注解_@RequestBody

image-20211221161108835

作用:将请求中JSON格式的参数转为JAVA对象

位置:写在方法参数前

1.AJAX请求发送JSON格式的参数

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>ajax请求 </title>
<script src="/js/jquery-2.1.1.min.js"></script>
<script>
$(function () {
$("#btn").click(function () {
var name =$("#name").val();
var sex =$("#sex").val();
var param = JSON.stringify({"name":name,"sex":sex});
$.ajax({
url:"/c8/addStudent2",
contentType:"application/json",
type:"post",
data:param,
success:function (data) {
console.log(data);
}
});
});
});
</script>
</head>
<body>
姓名:<input id="name"/><br/>
性别:<input id="sex"/><br/>
<input type="button" value="提交" id="btn"/>
</body>
</html>

2.编写控制器

 @PostMapping("/addStudent2")
// @ResponseBody
public Result addStudent(@RequestBody Student student)
{
System.out.println(student);
// 返回添加结果
Result result = new Result(true, "添加学生成功!");
return result;
}

SpringMVC文件上传_原生方式上传

image-20211221165611156

上传是Web工程中很常见的功能,SpringMVC框架简化了文件上传的代码,我们首先使用JAVAEE原生方式上传文件:

1.创建新的SpringMVC项目,在web.xml中将项目从2.3改为3.1,即可默认开启el表达式

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">

2.编写上传表单

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>上传</title>
</head>
<body>
<h3>文件上传</h3>
<%--上传表单的提交方式必须是post--%>
<%-- enctype属性为multipart/form-data,意思是不对表单数据进行编码 --%>
<form action="/fileUpload" method="post" enctype="multipart/form-data">
<%-- 文件选择控件,类型是file,必须要有name属性--%>
选择文件:<input type="file" name="upload"/>
<input type="submit" value="上传"/>
</form>
</body>
</html>

3.接受请求体数据:

@RequestMapping("/fileUpload")
public String upload(HttpServletRequest request) throws Exception {
// 获取输入流
ServletInputStream is = request.getInputStream();
// 从输入流获取请求体数据
int i = 0;
while ((i=is.read())!=-1){
System.out.println((char)i);
}
return "index";
}

接下来需要分析请求体中的文件项,并将数据写入磁盘,此时需要借助文件上传工具

1.引入文件上传依赖:

<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>

2.编写控制器接收上传请求,控制器进行三步操作

  1. 创建文件夹,存放上传文件。
  2. 分析请求体,找到上传文件数据。
  3. 将文件数据写入文件夹。
package com.itbaizhan.controller;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.List;

@Controller
public class UploadController {
@RequestMapping("/fileUpload")
public String upload(HttpServletRequest request) throws Exception {
// //获取输入流
// ServletInputStream inputStream = request.getInputStream();
// //从输入流获取请求体数据
// int i = 0;
// while ((i= inputStream.read())!=-1)
// {
// System.out.println((char) i);
// }

//创建文件夹,存放上传文件
//1.设置上传文件夹的真实路径
String realPath = request.getSession().getServletContext().getRealPath("/upload");
//2.判断该目录是否存在,如果不存在,创建该目录
File file = new File(realPath);
if(!file.exists())
{
file.mkdirs();
}

//分析请求体,找到上传文件数据
//1.创建磁盘文件工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//2.创建上传数据分析器对象
ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
//3.利用分析器对象解析请求体,返回所有数据项
List<FileItem> fileItems = servletFileUpload.parseRequest(request);
//4.遍历所有数据,找到文件项(非表单项)
for (FileItem fileItem : fileItems) {
if(!fileItem.isFormField())
{
//将文件数据写入文件夹
//1.获取文件名
String name = fileItem.getName();
//2.将文件写入磁盘
fileItem.write(new File(file,name));
//3.删除内存中的临时文件
fileItem.delete();
}
}
return "index";
}
}

SpringMVC文件上传_SpringMVC方式上传

image-20211221165812035

SpringMVC使用框架提供的文件解析器对象,可以直接将请求体中的文件数据转为MultipartFile对象,从而省略原生上传中分析请求体的步骤。

1.在SpringMVC核心配置文件配置文件解析器

<!-- 文件解析器对象,id名称必须是multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 支持一次上传文件的总容量。单位:字节 100M = 100*1024*1024-->
<property name="maxUploadSize" value="104857600"></property>
<!-- 文件名的编码方式-->
<property name="defaultEncoding" value="utf-8"></property>
</bean>

2.创建JSP表单

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>上传</title>
</head>
<body>
<h3>文件上传</h3>
<%--上传表单的提交方式必须是post--%>
<%-- enctype属性为multipart/form-data,意思是不对表单数据进行编码 --%>
<form action="/fileUpload2" method="post" enctype="multipart/form-data">
<%-- 文件选择控件,类型是file,必须要有name属性--%>
选择文件:<input type="file" name="file"/>
<input type="submit" value="上传"/>
</form>
</body>
</html>

3.编写控制器接受上传请求

// MultipartFile参数名必须和JSP文件空间的name属性一致
@RequestMapping("/fileUpload2")
public String upload2(MultipartFile file,HttpServletRequest request) throws IOException {
//创建文件夹,存放上传文件
String realPath = request.getSession().getServletContext().getRealPath("/upload");
File dir = new File(realPath);
if(!dir.exists())
{
dir.mkdirs();
}

//将上传的数据写到文件夹的文件中
//1.拿到上传的文件名
String originalFilename = file.getOriginalFilename();
originalFilename = UUID.randomUUID()+"_"+originalFilename;
//2.创建空文件
File newFile = new File(dir,originalFilename);
//3.将数据写入空文件中
file.transferTo(newFile);
return "index";
}

SpringMVC文件上传_上传多文件

SpringMVC支持一次性上传多个文件,写法如下:

1.创建JSP表单

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>上传</title>
</head>
<body>
<h3>文件上传</h3>
<%--上传表单的提交方式必须是post--%>
<%-- enctype属性为multipart/form-data,意思是不对表单数据进行编码 --%>
<form action="/fileUpload3" method="post" enctype="multipart/form-data">
<%-- 文件选择控件,类型是file,必须要有name属性--%>
用户名:<input name="username"><br/>
文件1:<input type="file" name="files"/><br/>
文件2:<input type="file" name="files"/><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>

2.编写控制器接收上传请求

// 处理多文件上传,参数类型为MultipartFile数组,参数名和JSP文件控件的name属性一致
@RequestMapping("/fileUpload3")
public String upload3(MultipartFile files[],String username,HttpServletRequest request) throws IOException {
System.out.println(username);
//1.设置上传文件保存的文件夹
String realPath = request.getSession().getServletContext().getRealPath("/upload");
File dir = new File(realPath);
if (!dir.exists()){
dir.mkdirs();
}

//2.遍历数组,将上传文件保存到文件夹
for(MultipartFile file:files)
{
String originalFilename = file.getOriginalFilename();
originalFilename = UUID.randomUUID()+"_"+originalFilename;
File newFile = new File(dir, originalFilename);
file.transferTo(newFile);
}
return "index";
}

SpringMVC文件上传_异步上传

image-20211221170609881

之前的上传答案,在上传成功后都会跳转页面。而在实际开发中,很多情况下上传后不进行跳转,而是进行页面的局部刷新,比如:上传头像成功后将头像显示在网页中。这时候就需要使用异步文件上传。

1.编写jsp页面,引入jQuery和jQuery表单上传工具jquery.form.js

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>上传</title>
<script src = "/js/jquery-2.1.1.min.js"></script>
<script src="/js/jquery.form.js"></script>
</head>
<body>
<h3>文件上传</h3>
<%--上传表单的提交方式必须是post--%>
<%-- enctype属性为multipart/form-data,意思是不对表单数据进行编码 --%>
<form enctype="multipart/form-data" id="ajaxForm">
图片上传:<input type="file" name="file"/>
<%-- 按钮类型不能是submit,否则会刷新页面 --%>
<input type="button" value="上传头像" id="btn"/>
</form>
<%--上传头像后展示的位置--%>
<img src="/" width="100" id="img">
<script>
$(function () {
$("#btn").click(function () {
//异步提交表单
$("#ajaxForm").ajaxSubmit(
{
url:"/fileUpload4",
type:"post",
success:function (data) {
$("#img").attr("src",data);
}
});
});
});
</script>
</body>
</html>

2.编写控制器接收异步上传请求

// MultipartFile参数名必须和JSP文件空间的name属性一致
@RequestMapping("/fileUpload4")
//不进行页面跳转,既不跳转到页面解析器
@ResponseBody
public String upload4(MultipartFile file,HttpServletRequest request) throws IOException {
//创建文件夹,存放上传文件
String realPath = request.getSession().getServletContext().getRealPath("/upload");
File dir = new File(realPath);
if(!dir.exists())
{
dir.mkdirs();
}

//将上传的数据写到文件夹的文件中
//1.拿到上传的文件名
String originalFilename = file.getOriginalFilename();
originalFilename = UUID.randomUUID()+"_"+originalFilename;
//2.创建空文件
File newFile = new File(dir,originalFilename);
//3.将数据写入空文件中
file.transferTo(newFile);
//返回文件的路径
return "/upload/"+originalFilename;
}

SpringMVC文件上传_跨服务器上传

image-20211221171301415

由于文件占据磁盘空间较大,在实际开发中往往会将文件上传到其他服务器中,此时需要使用跨服务器上传文件。

1.在tomcat的webapps下创建upload目录作为文件上传目录。

2.修改tomcat的conf/web.xml文件,支持跨服上传

<servlet>    
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
</servlet>

3.修改tomcat的conf/server.xml文件,修改tomcat端口,修改完开启tomcat服务器

<Connector port="8081" protocol="HTTP/1.1"               connectionTimeout="20000" redirectPort="8443" />

4.编写JSP上传表单

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>上传</title>
<script src = "/js/jquery-2.1.1.min.js"></script>
<script src="/js/jquery.form.js"></script>
</head>
<body>
<h3>文件上传</h3>
<%--上传表单的提交方式必须是post--%>
<%-- enctype属性为multipart/form-data,意思是不对表单数据进行编码 --%>
<form enctype="multipart/form-data" id="ajaxForm">
图片上传:<input type="file" name="file"/>
<%-- 按钮类型不能是submit,否则会刷新页面 --%>
<input type="button" value="上传头像" id="btn"/>
</form>
<%--上传头像后展示的位置--%>
<img src="/" width="100" id="img">
<script>
$(function () {
$("#btn").click(function () {
//异步提交表单
$("#ajaxForm").ajaxSubmit(
{
url:"/fileUpload5",
type:"post",
success:function (data) {
$("#img").attr("src",data);
}
});
});
});
</script>
</body>
</html>

5.添加跨服上传依赖

<!-- 跨服上传 -->
<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>

6.创建控制器方法,该方法在接受到上传请求后将文件保存到其他服务器上。

@RequestMapping("/fileUpload5")
@ResponseBody
public String upload4(HttpServletRequest request, MultipartFile file) throws Exception {
//设置跨服上传的服务器路径
String path = "http://localhost:8888/upload/";
//获取上传的文件名
String filename = file.getOriginalFilename();
filename = UUID.randomUUID()+"_"+filename;

//跨服上传;
//1.创建客户端对象
Client client = Client.create();
//2.使用客户端对象连接图片服务器
WebResource resource = client.resource(path + filename);
//3.传输数据
resource.put(file.getBytes());
return path+filename;
}

SpringMVC文件上传_文件下载

将文件上传到服务器后,有时我们需要让用户下载上传的文件,接下来我们编写文件下载功能:

查询所有可下载的文件

1.编写控制器方法,查询所有可下载的文件,并跳转到下载页面

@Controller
public class DownLoadController {
//查询可下载的文件
@RequestMapping("/showFiles")
public String showFileDown(HttpServletRequest request, Model model)
{
//1.获取下载文件路径集合
//注意:跨服务器上传中,网络路径将无法获取文件列表
String realPath = request.getSession().getServletContext().getRealPath("/upload");
File file = new File(realPath);
String[] files = file.list();
//2.将路径放入模型中,跳转到JSP页面
model.addAttribute("files",files);
return "download";
}

2.添加JSTL依赖

<!-- JSTL -->

<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-spec</artifactId>
<version>1.2.5</version>
</dependency>

<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>

3.编写下载页面

<%--
Created by IntelliJ IDEA.
User: 百里诀
Date: 2022/4/20
Time: 20:40
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>下载</title>
</head>
<body>
<h3>文件下载</h3>
<%--遍历文件集合--%>
<c:forEach items="${files}" var="file">
<a href="/download?fileName=${file}">${file}</a><br/>
</c:forEach>
</body>
</html>

编写下载控制器

// 文件下载
@RequestMapping("/download")
public void fileDown(HttpServletRequest request, HttpServletResponse response,String fileName) throws IOException {
// 设置响应头
response.setHeader("Content-Disposition","attachment;filename="+fileName);
// 获取文件路径
String path = request.getSession().getServletContext().getRealPath("/upload");
File file = new File(path,fileName);
// 获取字节输出流
ServletOutputStream os = response.getOutputStream();
// 使用输出流写出文件
os.write(FileUtils.readFileToByteArray(file));
os.flush();
os.close();
}

SpringMVC异常处理_单个控制器异常处理

image-20220420212234804

在系统当中, Dao、Service、Controller层代码出现都可能抛出异常。如果哪里产生异常就在哪里处理,则会降低开发效率。所以一般情况下我们会让异常向上抛出,最终到达DispatcherServlet中,此时SpringMVC提供了异常处理器进行异常处理,这样可以提高开发效率。

处理单个控制器的异常:

package com.itbaizhan.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController {
@RequestMapping("/t1")
public String t1()
{
String str = null;
// str.length();
// int flag = 1/0;
int[] arr = new int[1];
arr[2] = 10;
return "index";
}

/**
* 异常处理方法
* @param ex 异常对象
* @param model 模型对象
* @return
*/
// 添加@ExceptionHandler,表示该方法是处理异常的方法,属性为处理的异常类
@ExceptionHandler({java.lang.NullPointerException.class,java.lang.ArithmeticException.class})
public String exceptionHandler1(Exception ex, Model model)
{
//向模型中添加异常对象
model.addAttribute("msg",ex);
//跳转到异常页面
return "error";
}

//方法一不能处理的异常交给方法二来处理
@ExceptionHandler({java.lang.Exception.class})
public String exceptionHandler2(Exception ex, Model model)
{
//向模型中添加异常对象
model.addAttribute("msg",ex);
//跳转到异常页面
return "error2";
}
}

异常页面error.jsp

<%--
Created by IntelliJ IDEA.
User: 百里诀
Date: 2022/4/20
Time: 21:16
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>出错了!</title>
</head>
<body>
<h3>ERROR!!! 发生异常 ${msg}</h3>
</body>
</html>

异常页面error2.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>出错了!</title>
</head>

<body>
<h3>ERROR2 发生严重异常!${msg}</h3>
</body>
</html>

SpringMVC异常处理_全局异常处理

image-20211221171825754

在控制器中定义异常处理方法只能处理该控制器类的异常,要想处理所有控制器的异常,需要定义全局异常处理类。

1.编写另一个有异常的控制器类

@Controller
public class MyController2 {
@RequestMapping("/t2")
public String t2(){
int[] arr = new int[1];
arr[2] = 10;
return "index";
}
}

2.编写全局异常处理器类

package com.itbaizhan.controller;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

//全局异常处理器,需要添加@ControllerAdvice
@ControllerAdvice
public class GlobalExceptionHandler {

/**
* 异常处理方法
* @param ex 异常对象
* @param model 模型对象
* @return
*/
// 添加@ExceptionHandler,表示该方法是处理异常的方法,属性为处理的异常类
@ExceptionHandler({java.lang.NullPointerException.class,java.lang.ArithmeticException.class})
public String exceptionHandler1(Exception ex, Model model)
{
//向模型中添加异常对象
model.addAttribute("msg",ex);
//跳转到异常页面
return "error";
}

//方法一不能处理的异常交给方法二来处理
@ExceptionHandler({java.lang.Exception.class})
public String exceptionHandler2(Exception ex, Model model)
{
//向模型中添加异常对象
model.addAttribute("msg",ex);
//跳转到异常页面
return "error2";
}
}

SpringMVC异常处理_自定义异常处理器

image-20211221172137762

以上方式都是使用的SpringMVC自带的异常处理器进行异常处理,我们还可以自定义异常处理器处理异常:

package com.itbaizhan.controller;

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

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

// 自定义异常处理器实现HandlerExceptionResolver接口,并放入Spring容器中
@Component
public class MyExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
ModelAndView modelAndView = new ModelAndView();
if(e instanceof NullPointerException)
{
modelAndView.setViewName("error");
}else
{
modelAndView.setViewName("error2");
}
modelAndView.addObject("msg",e);
return modelAndView;
}
}

SpringMVC拦截器_拦截器简介

image-20211217145207400

SpringMVC的拦截器(Interceptor)也是AOP思想的一种实现方式。它与Servlet的过滤器(Filter)功能类似

主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。

拦截器和过滤器的区别

  • 拦截器是SpringMVC组件,而过滤器是Servlet组件。
  • 拦截器不依赖Web容器,过滤器依赖Web容器。
  • 拦截器只能对控制器请求起作用,而过滤器则可以对所有的请求起作用。
  • 拦截器可以直接获取IOC容器中的对象,而过滤器就不太方便获取。

SpringMVC拦截器_拦截器使用

1.使用maven创建SpringMVC的web项目

2.创建控制器方法

package com.itbaizhan.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController1 {
@RequestMapping("/m1")
public String m1()
{
System.out.println("控制器方法");
return "result";
}
}

3.创建拦截器类,该类实现HandlerInterceptor接口,需要重写三个方法:

  • preHandle:请求到达Controller前执行的方法,返回值为true通过拦截器,返回值为false被拦截器拦截。
  • postHandle:跳转到JSP前执行的方法
  • afterCompletion:跳转到JSP后执行的方法
package com.itbaizhan.interceptor;

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

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

//拦截器类
public class MyInterceptor implements HandlerInterceptor {
// 请求到达Controller前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("请求到达Controller前");
// 如果return false则无法到达Controller
return true;
}

// 跳转到JSP前执行,此时可以向Request域添加数据
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("跳转到JSP前");
request.setAttribute("name","百战");
}

// 跳转到JSP后执行,此时已经不能向Request域添加数据
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("跳转到JSP后");
request.setAttribute("age",10);
}
}

4.编写JSP页面

<%--
Created by IntelliJ IDEA.
User: 百里诀
Date: 2022/4/20
Time: 23:13
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>结果</title>
</head>
<body>
<h3>name:${requestScope.name}</h3>
<h3>age:${requestScope.age}</h3>
</body>
</html>

5.在SpringMVC核心配置文件中配置拦截器

<!-- 配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置拦截器的作用路径 -->
<mvc:mapping path="/**"/>
<!-- 拦截器对象 -->
<bean class="com.itbaizhan.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>

SpringMVC拦截器_全局拦截器

全局拦截器可以拦截所有控制器处理的URL,作用等于/**,配置方式如下:

<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 全局拦截器 -->
<bean class="com.itbaizhan.interceptor.MyInterceptor">
</bean>
</mvc:interceptors>

SpringMVC拦截器_拦截器链与执行顺序

image-20211221172301687

如果一个URL能够被多个拦截器所拦截,全局拦截器最先执行,其他拦截器根据配置文件中配置的从上到下执行,接下来我们再配置一个拦截器:

1.编写拦截器类

package com.itbaizhan.interceptor;

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

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

//拦截器类
public class MyInterceptor2 implements HandlerInterceptor {
// 请求到达Controller前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器2:请求到达Controller前");
// 如果return false则无法到达Controller
return true;
}

// 跳转到JSP前执行,此时可以向Request域添加数据
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器2:跳转到JSP前");

}

// 跳转到JSP后执行,此时已经不能向Request域添加数据
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("拦截器2:跳转到JSP后");

}
}

2.配置拦截器链(在springmvc.xml配置)

<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 拦截器1 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itbaizhan.interceptor.MyInterceptor"/>
</mvc:interceptor>

<!-- 拦截器2 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itbaizhan.interceptor.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>

访问控制器方法后输出如下:

image-20211217153441523

结论:

  1. preHandle()顺序执行,postHandle()、afterComletion()逆序执行。
  2. 只要有一个preHandle()拦截,后面的preHandle(),postHandle()都不会执行。
  3. 只要相应的preHandle()放行,afterComletion()就会执行。

SpringMVC跨域请求_同源策略

image-20211221172937329

同源策略是浏览器的一个安全功能。同源,指的是两个URL的协议,域名,端口相同。浏览器出于安全方面的考虑,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。

哪些不受同源策略限制:

  1. 页面中的<a>跳转、表单提交不会受到同源策略限制的。
  2. 静态资源引入也不会受到同源策略限制。如嵌入到页面中的<script src=""><img src=""><link href="">等。
  3. 最容易收到同源策略影响的就是Ajax请求。

SpringMVC跨域请求_跨域请求

image-20211221173152117

当请求URL的协议、域名、端口三者中任意一个与当前页面URL不同时即为跨域。浏览器执行JavaScript脚本时,会检查当前请求是否同源,如果不是同源资源,就不会被执行。

当前页面URL 被请求页面URL 是否跨域 原因
http://www.itbaizhan.com/ http://www.itbaizhan.com/index.html
http://www.itbaizhan.com/ https://www.itbaizhan.com/index.html 跨域 协议不同
http://www.itbaizhan.com/ http://www.baidu.com/ 跨域 主域名不同
http://www.itbaizhan.com/ http://itbz.itbaizhan.com/ 跨域 子域名不同
http://www.itbaizhan.com:8080/ http://www.itbaizhan.com:7001/ 跨域 端口号不同

1.编写控制器方法

@Controller
@ResponseBody
public class MyController3 {
@RequestMapping("/m3")
public String m3(Model model)
{
System.out.println("测试跨域请求");
return "success";
}

2.编写JSP页面,发送异步请求

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>跨域请求</title>
<script src="/js/jquery-2.1.1.min.js"></script>
<script>
$(function () {
$("#btn").click(function () {
// $.get("http://localhost:8080/m3",function (data) {
// console.log(data);
// })
$.get("http://127.0.0.1:8080/m3", function (data) {
console.log(data);
});
});
});
</script>
</head>
<body>
<button id="btn">异步请求</button>
</body>
</html>

结果:

当浏览器通过http://localhost:8080/cross.jsp访问JSP页面时

image-20211217171651760

SpringMVC跨域请求_控制器接收跨域请求

image-20211221173320233

SpringMVC提供了注解@CrossOrigin解决跨域问题。用法如下:

@RequestMapping("/m3")
@ResponseBody
// 如果请求从http://localhost:8080发出,则允许跨域访问
@CrossOrigin("http://localhost:8080")
public String m3(){
System.out.println("测试跨域请求");
return "success";
}

SSM整合_需求分析

接下来我们使用Maven+Spring+MyBatis+SpringMVC完成一个案例,案例需求为在页面可以进行添加学生+查询所有学生!

案例需要使用以下技术:

  • 使用Maven创建聚合工程,并使用Maven的tomcat插件运行工程
  • 使用Spring的IOC容器管理对象
  • 使用MyBatis操作数据库
  • 使用Spring的声明式事务进行事务管理
  • 使用SpringMVC作为控制器封装Model并跳转到JSP页面展示数据
  • 使用Junit测试方法
  • 使用Log4j在控制台打印日志

案例的编写流程如下:

  1. 创建maven父工程,添加需要的依赖和插件
  2. 创建dao子工程,配置MyBatis操作数据库,配置Log4j在控制台打印日志。
  3. 创建service子工程,配置Spring声明式事务
  4. 创建controller子工程,配置SpringMVC作为控制器,编写JSP页面展示数据。
  5. 每个子工程都使用Spring进行IOC管理
# 准备数据库数据
CREATE DATABASE `student`;
USE `student`;
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) DEFAULT NULL,
`sex` VARCHAR(10) DEFAULT NULL,
`address` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB CHARSET=utf8;
INSERT INTO `student`(`id`,`name`,`sex`,`address`) VALUES (1,'百战程序员','男','北京'),(2,'北京尚学堂','女','北京');

SSM整合_创建父工程

创建maven父工程,添加需要的依赖和插件

<?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.itbaizhan</groupId>
<artifactId>ssm_demo</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<!--Spring版本-->
<spring.version>5.2.12.RELEASE</spring.version>
</properties>

<dependencies>
<!-- mybaits -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>

<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>

<!-- druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>

<!-- MyBatis与Spring的整合包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>

<!-- springmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

<!-- 事务 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
<!-- jstl -->
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-spec</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>

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

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

<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>

<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
</dependencies>

<build>
<plugins>
<!-- tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8080</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
<server>tomcat7</server>
<systemProperties>
<java.util.logging.SimpleFormatter.format>%1$tH:%1$tM:%1$tS %2$s%n%4$s: %5$s%6$s%n
</java.util.logging.SimpleFormatter.format>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
</project>

SSM整合_创建dao子工程

1.在父工程下创建maven普通java子工程

2.编写实体类

package com.itbaizhan.domain;

public class Student {
private int id;
private String name;
private String sex;
private String address;

@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}

public Student() {
}

public Student(int id, String name, String sex, String address) {
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

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

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}
}

3.编写持久层接口

package com.itbaizhan.dao;

import com.itbaizhan.domain.Student;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface StudentDao {
//查询所有学生
@Select("select * from stduent")
List<Student> findAll();

//添加学生
@Insert("insert into student values(null.#{name},#{sex},#{address})")
void add(Student student);
}

4.编写log4j.properties配置文件

log4j.rootCategory=debug, CONSOLE, LOGFILE
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%d{MM/dd HH:mm:ss}] %-6r [%15.15t] %-5p %30.30c %x - %m\n

5.编写数据库配置文件druid.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///student
jdbc.username=root
jdbc.password=root

6.编写MyBatis配置文件SqlMapConfig.xml

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

7.编写Spring配置文件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">

<!-- 读取数据库配置文件 -->
<context:property-placeholder location="classpath:druid.properties"></context:property-placeholder>

<!-- 配置数据源 -->
<bean id="dataSouce" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>

<!-- SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSouce"></property>
<property name="configLocation" value="classpath:SqlMapConfig.xml"></property>
</bean>

<!-- 配置扫描包对象,为包下的接口创建代理对象 -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.itbaizhan.dao"></property>
</bean>


</beans>

8.测试持久层接口的方法

package com.itbaizhan.dao;

import com.itbaizhan.domain.Student;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext-dao.xml")
public class StudentDaoTest {
@Autowired
private StudentDao studentDao;
@Test
public void testFindAll()
{
List<Student> all = studentDao.findAll();
for (Student student : all) {
System.out.println(student.toString());
}
}

@Test
public void testAdd(){
Student student = new Student(0, "wwww", "ewg", "fsf");
studentDao.add(student);
}
}

SSM整合_创建service子工程

  1. 在父工程下创建maven普通java子工程

  2. service子工程引入dao子工程的依赖

<dependencies>
<dependency>
<groupId>com.itbaizhan</groupId>
<artifactId>ssm_dao</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>

3.创建服务层方法

@Service
public class StudentService {
@Autowired
private StudentDao studentDao;
public List<Student> findAllStudent(){
return studentDao.findAll();
}

public void addStudent(Student student){
studentDao.add(student);
}
}

4.创建服务层的Spring配置文件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: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">

<!-- 包扫描 -->
<context:component-scan base-package="com.itbaizhan.service"></context:component-scan>

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

<!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

<!-- 切面 -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itbaizhan.service.*.*(..))"></aop:advisor>
</aop:config>
</beans>

SSM整合_创建controller子工程

1.在父工程下使用maven创建web类型子工程

2.controller工程引入service子工程的依赖,并配置ssm父工程

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.itbaizhan</groupId>
<artifactId>ssm_controller</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<parent>
<artifactId>ssm_demo</artifactId>
<groupId>com.itbaizhan</groupId>
<version>1.0-SNAPSHOT</version>
</parent>

<dependencies>
<dependency>
<groupId>com.itbaizhan</groupId>
<artifactId>ssm_service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

3.编写控制器类

@Controller
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;

@RequestMapping("/all")
public String all(Model model)
{
List<Student> allStudent = studentService.findAllStudent();
model.addAttribute("students",allStudent);
return "allStudent";
}

@RequestMapping("/add")
public String add(Student student)
{
studentService.addStudent(student);
//重定向到查询所有学生
return "redirect:/student/all";
}
}

4.编写SpringMVC配置文件springmvc.xml

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

<!-- 扫描Controller包 -->
<context:component-scan base-package="com.itbaizhan.controller"></context:component-scan>

<!-- 配置视图解析器 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>

<!-- 开启SpringMVC注解的支持 -->
<mvc:annotation-driven/>
<!-- 放行静态资源 -->
<mvc:default-servlet-handler/>
</beans>

5.编写Spring的总配置文件applicationContext.xml,该文件引入dao和service层的Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<import resource="applicationContext-dao.xml"></import>
<import resource="applicationContext-service.xml"></import>
</beans>

6.在web.xml中配置Spring监听器,该监听器会监听服务器启动,并自动创建Spring的IOC容器

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

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

<!-- 创建spring容器的监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
</web-app>

7.在web.xml中配置SpringMVC的前端控制器和编码过滤器

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

<display-name>Archetype Created Web Application</display-name>
<!--前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</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>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<!--编码过滤器-->
<filter>
<filter-name>encFilter</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>
</filter>
<filter-mapping>
<filter-name>encFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!-- 创建spring容器的监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
</web-app>

8.编写JSP页面allStudent.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>所有学生</title>
</head>
<body>
<%-- 添加学生表单 --%>
<form action="/student/add" method="post">
姓名:<input name="name">
性别:<input name="sex">
地址:<input name="address">
<input type="submit" value="提交">
</form>

<%-- 展示学生表格 --%>
<table width="500" cellpadding="0" cellspacing="0" border="1" align="center">
<tr>
<th>id</th>
<th>姓名</th>
<th>性别</th>
<th>地址</th>
</tr>
<c:forEach items="#{students}" var="student">
<tr>
<td>${student.id}</td>
<td>${student.name}</td>
<td>${student.sex}</td>
<td>${student.address}</td>
</tr>
</c:forEach>
</table>
</body>
</html>