本笔记为本人大学期间自主学习时整理而成,为了更好的学习,将其整理,分享。
SpringMVC概述
SpringMVC简介
SpringMVC是属于Spring框架内的一个模块,可以看作专门用于web开发的小框架。
SpringMVC可以理解为servlet的升级。它在servlet的基础上面添加了一些功能,使开发人员开发web更加方便。
SpringMVC就是一个Spring。它也可以像Spring一样看作一个容器,只是这是一个存放控制器对象的容器。
开发人员需要做的工作就是使用注解@Controller创建控制器对象,并放在SpringMVC容器中。
控制器对象就像一个servlet一样能够接受用户请求,显示处理结果。但它是一个普通类,并不是Servlet。SpringMVC赋予了它特殊功能。
SpringMVC中有一个Servlet:DispatcherServlet
(称之为“中央调度器”),它负责接收用户的所有请求,并转发给控制器对象,由控制器对象处理请求。
SpringMVC优点
(1)基于MVC架构。功能明确,解耦合。
(2)轻量、简单、易学。
(3)作为Spring框架的一部分,能够使用IoC、AOP,能够方便的整合其他框架。
(4)Spring强化注解的使用。在控制器,Service,Dao 都可以使用注解。方便灵活。
使用@Controller 创建处理器对象,@Service 创建业务对象,@Autowired 或者@Resource
在控制器类中注入 Service, Service 类中注入 Dao。
流程
index.jsp—–DispatherServlet(Servlet)—–转发,分配给—–Controller对象(@Controller注解创建的对象)
第一个SpringMVC程序
原始写法,不用注解的方式:
1.web.xml中加入:
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
2.类路径下创建config目录,新建springmvc配置文件:
<?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
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置处理器适配器 -->
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
<!--配置处理器映射器 -->
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<!--配置处理器 -->
<bean name="/hello.do" class="com.neu.controller.HelloController" />
</beans>
3.编写控制器,实现Controller接口,重写方法:
package com.neu.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
ModelAndView mav = new ModelAndView();
mav.addObject("hello", "hello,springmvc!!!");
mav.setViewName("index.jsp");
return mav;
}
}
4.编写index.jsp页面:
${hello}
使用注解方式:
新建maven Web项目
创建空项目,在下面创建maven模块,选择maven-archetype-webapp模板。
在src/main
目录新建java
目录,右键Mark Directory as-->Sources Root
在src/main
目录下新建resources
目录,右键Mark Directory as-->Resources Root
修改web.xml的约束版本:
默认生成的为:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>
可以看到web.xml约束版本较低。
修改方法:
点击File–>Project Stucture–>Modules–>点开创建的module
–>点击web–>将Deployment Descriptors中的那个配置删掉(点击减号)
–>再点击加号新增一个web.xml配置,命名为web1.xml,版本选择4.0–>确定、应用
–>将webapp/WEB-INF中的web1.xml重新修改成web.xml(修改快捷键为shift+F6
)
新生成的web.xml为:
<?xml version="1.0" encoding="UTF-8"?>
<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_4_0.xsd"
version="4.0">
</web-app>
pom.xml的配置
删除无关的依赖,添加servlet,jsp,spring-webmvc
依赖
添加spring-webmvc依赖后,maven会自动将spring的spring-aop、spring-beans、spring-context、spring-core、spring-expression、spring-web等依赖加入到项目中。
<?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.kwxy</groupId>
<artifactId>my_springmvc</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--servlet依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<!--jsp依赖-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<!--springmvc依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<!--filtering 选项 false 不启用过滤器, *.property 已经起到过滤的作用了 -->
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
记得添加资源插件。
注册中央调度器
在web.xml中注册一个servlet:DispatcherServlet,是HttpServlet的子类,称为中央调度器,也被称作前端控制器(front controller)。其作用在上面介绍过。
这个角色是SpringMVC项目的标志,扮演重要角色。
在注册这个对象时,同时设置在启动Tomcat服务器时创建这个对象。
因为在创建DispatcherServlet同时,会创建SpringMVC容器,读取SpringMVC配置文件,把这个文件中的对象都创建好,这样用户访问时就可以直接使用了。
在默认情况下,中央调度器对象在创建时回到以下目录中寻找SpringMVC配置文件:
“/WEB-INF/<servlet-name>
-servlet.xml” 其中servletname表示这个标签中的内容。
其中这个servlet-name是自己在web.xml中自定义配置的。
如果默认寻找的配置文件和自己定义的配置文件不一样的话,启动tomcat就会报异常说找不到文件。
通常情况下可以设置contextConfigLocation这个初始化参数来修改这一默认规则,在指定目录下寻找配置文件。
web.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<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_4_0.xsd"
version="4.0">
<!--声明,注册springmvc的核心对象DispatcherServlet
需要在tomcat服务器启动后,创建DispatcherServlet对象的实例。
为什么要创建DispatcherServlet对象的实例呢?
因为DispatcherServlet在他的创建过程中, 会同时创建springmvc容器对象,
读取springmvc的配置文件,把这个配置文件中的对象都创建好, 当用户发起
请求时就可以直接使用对象了。
servlet的初始化会执行init()方法。DispatcherServlet在init()中{
//创建容器,读取配置文件
WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");
//把容器对象放入到ServletContext中
getServletContext().setAttribute(key, ctx);
}
springmvc创建容器对象时,读取的配置文件默认是/WEB-INF/<servlet-name>-servlet.xml .
-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--自定义springmvc读取的配置文件的位置-->
<init-param>
<!--springmvc的配置文件的位置的属性-->
<param-name>contextConfigLocation</param-name>
<!--指定自定义文件的位置-->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--在tomcat启动后,创建Servlet对象
load-on-startup:表示tomcat启动后创建对象的顺序。它的值是整数,数值越小,
tomcat创建对象的时间越早。 大于等于0的整数。
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--
使用框架的时候, url-pattern可以使用两种值
1. 使用扩展名方式, 语法 *.xxxx , xxxx是自定义的扩展名。 常用的方式 *.do, *.action, *.mvc等等
不能使用 *.jsp
http://localhost:8080/myweb/some.do
http://localhost:8080/myweb/other.do
2.使用斜杠 "/"
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
自定义配置文件路径为classpath:springmvc.xml,就在resources目录下创建spring配置文件,名字叫做springmvc.xml,注意是spring配置文件,不是普通文件。
创建请求页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<p>第一个SpringMVC项目</p>
<p><a href="some.do">发送some.do请求</a></p>
</body>
</html>
创建处理器
包名为com.kwxy.controler。
在类上添加@Controller注解,这个类就成了控制器、处理器,称之为后端控制器:banck controller 在类中的方法上添加@RequestMapping注解。使用@RequestMapping修饰的方法叫做处理器方法或控制器方法,用来处理请求,相当于servlet中的service方法。
返回值:ModelAndView Model:显示给用户的数据, View:视图,如jsp等
package com.kwxy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* @Controller:创建处理器对象,对象放在springmvc容器中。 位置:在类的上面
* 和Spring中讲的@Service ,@Component
* <p>
* 能处理请求的都是控制器(处理器):MyController能处理请求,
* 叫做后端控制器(back controller)
* <p>
* 没有注解之前,需要实现各种不同的接口才能做控制器使用
*/
@Controller
public class MyController {
/*
处理用户提交的请求,springmvc中是使用方法来处理的。
方法是自定义的, 可以有多种返回值, 多种参数,方法名称自定义
*/
/**
* 准备使用doSome方法处理some.do请求。
*
* @RequestMapping: 请求映射,作用是把一个请求地址和一个方法绑定在一起。
* 一个请求指定一个方法处理。
* 属性:1. value 是一个String数组,表示请求的uri地址的。
* value可以有多个值,用{}括住,用逗号,分隔 在使用时,推荐地址以“/”
* 位置:1.在方法的上面,常用的。
* 2.在类的上面
* 说明: 使用RequestMapping修饰的方法叫做处理器方法或者控制器方法。
* 使用@RequestMapping修饰的方法可以处理请求的,类似Servlet中的doGet, doPost
*
* 返回值:ModelAndView 表示本次请求的处理结果
* Model: 数据,请求处理完成后,要显示给用户的数据
* View: 视图, 比如jsp等等。
*/
@RequestMapping(value = "/some.do")
public ModelAndView doSome() { // doGet()--service请求处理
//处理some.do请求了。 相当于service调用处理完成了。
ModelAndView mv = new ModelAndView();
//添加数据, 框架在请求的最后把数据放入到request作用域。
//request.setAttribute("msg","欢迎使用springmvc做web开发");
mv.addObject("msg", "欢迎使用springmvc做web开发");
mv.addObject("fun", "执行的是doSome方法");
//指定视图, 指定视图的完整路径
//框架对视图执行的forward操作, request.getRequestDispather("/show.jsp).forward(request,response)
mv.setViewName("/show.jsp");
//返回mv
return mv;
}
}
声明组件扫描器
在 springmvc.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 https://www.springframework.org/schema/context/spring-context.xsd">
<!--声明组件扫描器-->
<context:component-scan base-package="com.kwxy.controller"/>
</beans>
定义目标页面
在webapp目录下的show.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>show.jsp从请求作用域获取数据</title>
</head>
<body>
<h3>msg数据:${msg}</h3>
<br>
<h3>fun数据:${fun}</h3>
</body>
</html>
现在启动项目可以直接访问了,并且能够得到数据。
创建视图解析器
<!-- 启用spring的一些annotation -->
<context:annotation-config/>
在当前项目中存在一个问题:用户可以通过地址栏直接访问show.jsp。
为了保护show.jsp的访问权限,可以将它放在WEB-INF目录或子目录下,(WEB-INF)对用户来说是不可见的。
这样修改控制器中ModelAndView的ViewName到show.jsp的实际路径就可以解决这个问题。
SpringMVC可以简化setViewName参数冗长的字符串,通过配置视图解析器来实现。
SpringMVC 框架为了避免对于请求资源路径与扩展名上的冗余,在视图解析器InternalResouceViewResolver 中引入了请求的前辍与后辍。
而 ModelAndView 中只需给出要跳转页面的文件名即可,对于具体的文件路径与文件扩展名,视图解析器会自动完成拼接。
比如在WEB-INF中创建view文件夹,将show.jsp放到view文件夹中。
在springmvc.xml中配置视图解析器:(InternalResourceViewResolver)
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
在控制器的doSome方法中,将mv.setViewName("/show.jsp");
写成mv.setViewName("show");
配置视图解析器之后,就不能使用完整路径,否则会报404错误。
使用 SpringMVC 框架的web请求处理顺序

springmvc请求的处理流程
1)发起some.do
2)tomcat(web.xml–url-pattern知道 *.do的请求给DispatcherServlet)
3)DispatcherServlet(根据springmvc.xml配置知道 some.do—doSome())
4)DispatcherServlet把some.do转发个MyController.doSome()方法
5)框架执行doSome()把得到ModelAndView进行处理, 转发到show.jsp
SpringMV注解式开发
@RequestMapping定义请求规则
@RequestMapping在控制器类上面的使用:
其value属性是此类中每个方法对应的请求路径(也就是 @RequestMapping注解的value属性值)的开头公共部分。
例如,某个控制器类的每个请求方法的 @RequestMapping注解为:@RequestMapping("/user/XXX.XXX")
。
那么可以在这个控制器类添加注解@RequestMapping("/user")
,而每个请求方法只写@RequestMapping("/XXX.XXX").
method属性指定请求方法:
属性值是枚举类型RequestMethod
,常用值RequestMethod.GET
和RequestMethod.POST
。
当未指定请求方式时,无论哪种请求都会成功,
当请求方式与指定方式不匹配
时,报错:405 Request method is not supported
。
各种请求方式对应的提交方式:
序号 | 请求方式 | 提交方式 |
---|---|---|
1 | 表单请求 | 默认get,可以指定为post |
2 | AJAX请求 | 默认get,可以指定为post |
3 | 地址栏请求 | get请求 |
4 | 超链接请求 | get请求 |
5 | src资源路径请求 | get请求 |
参照代码:
/**
* @RequestMapping:
* value : 所有请求地址的公共部分,叫做模块名称
* 位置: 放在类的上面
*/
@Controller
@RequestMapping("/user")
public class MyController {
/**
* @RequestMapping : 请求映射
* 属性:method, 表示请求的方式。 它的值RequestMethod类枚举值。
* 例如表示get请求方式, RequestMethod.GET
* post方式, RequestMethod.POST
*
* 你不用get方式,错误是:
* HTTP Status 405 - Request method 'GET' not supported
*/
//指定some.do使用get请求方式
@RequestMapping(value = "/some.do",method = RequestMethod.GET)
public ModelAndView doSome(){ // doGet()--service请求处理
//处理some.do请求了。 相当于service调用处理完成了。
ModelAndView mv = new ModelAndView();
mv.addObject("msg","欢迎使用springmvc做web开发");
mv.addObject("fun","执行的是doSome方法");
mv.setViewName("show");
return mv;
}
//指定other.do是post请求方式
@RequestMapping(value = "/other.do",method = RequestMethod.POST)
public ModelAndView doOther(){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","====欢迎使用springmvc做web开发====");
mv.addObject("fun","执行的是doOther方法");
mv.setViewName("other");
return mv;
}
//不指定请求方式,没有限制
@RequestMapping(value = "/first.do")
public ModelAndView doFirst(HttpServletRequest request,
HttpServletResponse response,
HttpSession session){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","====欢迎使用springmvc做web开发====" + request.getParameter("name"));
mv.addObject("fun","执行的是doFirst方法");
mv.setViewName("other");
return mv;
}
处理器方法的参数
处理器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,即程序员可在方法内直接使用。
➢ HttpServletRequest
➢ HttpServletResponse
➢ HttpSession
➢ 请求中所携带的请求参数
逐个参数接收
只要保证请求参数名与该请求处理方法的参数名相同即可。
index.jsp:
<p>请求参数名和处理器方法的形参名一样</p>
<form action="receiveproperty.do" method="post">
姓名:<input type="text" name="name"> <br/>
年龄:<input type="text" name="age"> <br/>
<input type="submit" value="提交参数">
</form>
MyController:
/**
* 逐个接收请求参数:
* 要求: 处理器(控制器)方法的形参名和请求中参数名必须一致。
* 同名的请求参数赋值给同名的形参
* 框架接收请求参数
* 1. 使用request对象接收请求参数
* String strName = request.getParameter("name");
* String strAge = request.getParameter("age");
* 2. springmvc框架通过 DispatcherServlet 调用 MyController的doSome()方法
* 调用方法时,按名称对应,把接收的参数赋值给形参
* doSome(strName,Integer.valueOf(strAge))
* 框架会提供类型转换的功能,能把String转为 int ,long , float, double等类型。
*
* 400状态码是客户端错误, 表示提交请求参数过程中,发生了问题。
*/
@RequestMapping(value = "/receiveproperty.do")
public ModelAndView doSome(String name, Integer age){
System.out.println("doSome, name="+name+" age="+age);
//可以在方法中直接使用 name , age
//处理some.do请求了。 相当于service调用处理完成了。
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",Integer.valueOf(age));
//show是视图文件的逻辑名称(文件名称)
mv.setViewName("show");
return mv;
}
解决请求参数包含中文的乱码问题
get请求方式没有乱码,post请求方式有乱码。
对于前面所接收的请求参数,若含有中文,则会出现中文乱码问题。
Spring 对于请求参数中的中文乱码问题,给出了专门的字符集过滤器:spring-web-5.2.4.RELEASE.jar 的 org.springframework.web.filter 包下的 CharacterEncodingFilter
类。
解决方案
在 web.xml 中注册字符集过滤器,即可解决 Spring 的请求参数的中文乱码问题。
不过,最好将该过滤器注册在其它过滤器之前。因为过滤器的执行是按照其注册顺序进行的。
<!--注册声明过滤器,解决post请求乱码的问题-->
<filter>
<filter-name>characterEncodingFilter</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>
<!--强制请求对象(HttpServletRequest)使用encoding编码的值-->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!--强制应答对象(HttpServletResponse)使用encoding编码的值-->
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<!--
/*:表示强制所有的请求先通过过滤器处理。
-->
<url-pattern>/*</url-pattern>
</filter-mapping>
校正请求参数名@RequestParam
所谓校正请求参数名,是指若请求 URL 所携带的参数名称与处理方法中指定的参数名不相同时,
则需在处理方法参数前,添加一个注解@RequestParam(“请求参数名”)
,指定请求 URL 所携带参数的名称。
该注解是对处理器方法参数进行修饰的。value 属性指定请求参数的名称。
index.jsp:
<p>请求参数名和处理器方法的形参名不一样</p>
<form action="receiveparam.do" method="post">
姓名:<input type="text" name="rname"> <br/>
年龄:<input type="text" name="rage"> <br/>
<input type="submit" value="提交参数">
</form>
MyController:
/**
* 请求中参数名和处理器方法的形参名不一样
* @RequestParam: 逐个接收请求参数中, 解决请求中参数名形参名不一样的问题
* 属性:1. value 请求中的参数名称
* 2. required 是一个boolean,默认是true
* true:表示请求中必须包含此参数。
false:可以没有此参数。
* 位置: 在处理器方法的形参定义的前面
*/
@RequestMapping(value = "/receiveparam.do")
public ModelAndView receiveParam(@RequestParam(value = "rname",required = false) String name,
@RequestParam(value = "rage",required = false) Integer age){
System.out.println("doSome, name="+name+" age="+age);
//可以在方法中直接使用 name , age
//处理some.do请求了。 相当于service调用处理完成了。
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
//show是视图文件的逻辑名称(文件名称)
mv.setViewName("show");
return mv;
}
注意:
不携带此参数不等同于携带此参数但没有值。例如在表单中,即使没有填写某项参数就提交了,但请求依然会携带这个参数(只要此标签有name属性),只是值为空字符串而已。
使用对象接收参数
将处理器方法的参数定义为一个对象,只要保证请求参数名与这个对象的属性同名即可。
定义Student类:
//保存请求参数值的一个普通类
public class Student {
// 属性名和请求中参数名一样
private String name;
private Integer age;
public Student() {
System.out.println("===Student的无参数构造方法===");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("setName"+name);
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
System.out.println("setAge"+age);
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
index.jsp:
<p>使用java对象接收请求参数</p>
<form action="receiveobject.do" method="post">
姓名:<input type="text" name="name"> <br/>
年龄:<input type="text" name="age"> <br/>
<input type="submit" value="提交参数">
</form>
MyController:
/**
* 处理器方法形参是java对象, 这个对象的属性名和请求中参数名一样的
* 框架会创建形参的java对象, 给属性赋值。 请求中的参数是name,框架会调用setName()
* @return
*/
@RequestMapping(value = "/receiveobject.do")
public ModelAndView receiveParam( Student myStudent){
System.out.println("receiveParam, name="+myStudent.getName()+" age="+myStudent.getAge());
//可以在方法中直接使用 name , age
//处理some.do请求了。 相当于service调用处理完成了。
ModelAndView mv = new ModelAndView();
mv.addObject("myname",myStudent.getName());
mv.addObject("myage",myStudent.getAge());
mv.addObject("mystudent",myStudent);
//show是视图文件的逻辑名称(文件名称)
mv.setViewName("show");
return mv;
}
处理器方法的返回值
使用@Controller 注解的处理器的处理器方法,其返回值常用的有四种类型:
➢ 第一种:ModelAndView
➢ 第二种:String
➢ 第三种:无返回值 void
➢ 第四种:返回自定义类型对象
根据不同的情况,使用不同的返回值。
(1)ModelAndView: 有数据和视图,对视图执行forward。
(2)String:表示视图,可以逻辑名称,也可以是完整视图路径
(3)void: 不能表示数据,也不能表示视图。
在处理ajax的时候,可以使用void返回值。通过HttpServletResponse输出数据。响应ajax请求。
ajax请求服务器端返回的就是数据, 和视图无关。
(4)Object:例如String , Integer , Map,List, Student等等都是对象,
对象有属性, 属性就是数据。所以返回Object表示数据, 和视图无关。
可以使用对象表示的数据,响应ajax请求。
返回ModelAndView
若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时处理器方法返回 ModelAndView 比较好。
当然,若要返回 ModelAndView,则处理器方法中需要定义 ModelAndView 对象。
在使用时,若该处理器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何资源跳转(如对页面的 Ajax 异步响应),
此时若返回 ModelAndView,则将总是有一部分多余:要么 Model 多余,要么 View 多余。即此时返回 ModelAndView 将不合适。
1.最普遍的方式就是通过MOdelAndView,配置文件中需要配置视图解析器,其他的不再细说。
2.通过modelmap,这两种方式最大的区别就是使用ModelMap不需要配置视图解析器.处理方法只需要在方法参数中添加ModelMap。
之前的的例子中用的就是这种方式。
返回String
表示视图,只完成页面跳转工作,可以逻辑名称,也可以是完整视图路径
例如:
逻辑视图名称:
/**
* 处理器方法返回String--表示逻辑视图名称,需要配置视图解析器
*/
@RequestMapping(value = "/returnString-view.do")
public String doReturnView(HttpServletRequest request,String name, Integer age){
System.out.println("doReturnView, name="+name+" age="+age);
//可以自己手工添加数据到request作用域
request.setAttribute("myname",name);
request.setAttribute("myage",age);
// show : 逻辑视图名称,项目中配置了视图解析器
// 框架对视图执行forward转发操作
return "show";
}
完整视图路径:
//处理器方法返回String,表示完整视图路径, 此时不能配置视图解析器
@RequestMapping(value = "/returnString-view2.do")
public String doReturnView2(HttpServletRequest request,String name, Integer age){
System.out.println("===doReturnView2====, name="+name+" age="+age);
//可以自己手工添加数据到request作用域
request.setAttribute("myname",name);
request.setAttribute("myage",age);
// 完整视图路径,项目中不能配置视图解析器
// 框架对视图执行forward转发操作
// /WEB-INF/view//WEB-INF/view/show.jsp.jsp
// /WEB-INF/view/WEB-INF/view/show.jsp.jsp
return "/WEB-INF/view/show.jsp";
}
返回void(了解)
不能表示数据,也不能表示视图。
一般的使用场景:处理AJAX请求。
通过HttpServletResponse输出数据。
(1)创建项目,添加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
(2)引入jQuery库
(3)定义index.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.4.1.js"></script>
<script type="text/javascript">
$(function(){
$("button").click(function(){
//alert("button click");
$.ajax({
//url:"returnVoid-ajax.do",
//url:"returnStudentJsonArray.do",
url:"returnStringData.do",
data:{
name:"zhangsan",
age:20
},
type:"post",
dataType:"text",
//dataType:"json",
success:function(resp){
//resp从服务器端返回的是json格式的字符串 {"name":"zhangsan","age":20}
//jquery会把字符串转为json对象, 赋值给resp形参。
// [{"name":"李四同学","age":20},{"name":"张三","age":28}]
//alert(resp.name + " "+resp.age);
/*$.each(resp,function(i,n){
alert(n.name+" "+n.age)
})*/
alert("返回的是文本数据:"+resp);
}
})
})
})
</script>
</head>
<body>
<button id="btn">发起ajax请求</button>
</body>
</html>
(4)在控制器中处理并响应请求
//处理器方法返回void, 响应ajax请求
//手工实现ajax,json数据: 代码有重复的 1. java对象转为json;2. 通过HttpServletResponse输出json数据
@RequestMapping(value = "/returnVoid-ajax.do")
public void doReturnVoidAjax(HttpServletResponse response, String name, Integer age) throws IOException {
System.out.println("===doReturnVoidAjax====, name="+name+" age="+age);
//处理ajax, 使用json做数据的格式
//service调用完成了, 使用Student表示处理结果
Student student = new Student();
student.setName("张飞同学");
student.setAge(28);
String json = "";
//把结果的对象转为json格式的数据
if( student != null){
ObjectMapper om = new ObjectMapper();
json = om.writeValueAsString(student);
System.out.println("student转换的json===="+json);
}
//输出数据,响应ajax的请求
response.setContentType("application/json;charset=utf-8");
PrintWriter pw = response.getWriter();
pw.println(json);
pw.flush();
pw.close();
}
返回Object
处理器方法也可以返回 Object 对象。这个 Object 可以是 Integer,String,自定义对象,Map,List 等。
但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的。
返回对象,需要使用@ResponseBody 注解,将转换后的 JSON 数据放入到响应体中。
springmvc处理器方法返回Object, 可以转为json输出到浏览器,响应ajax的内部原理
1. <mvc:annotation-driven> 注解驱动。
注解驱动实现的功能是 完成java对象到json,xml, text,二进制等数据格式的转换。
<mvc:annotation-driven>在加入到springmvc配置文件后, 会自动创建HttpMessageConverter接口
的7个实现类对象, 包括 MappingJackson2HttpMessageConverter (使用jackson工具库中的ObjectMapper实现java对象转为json字符串)
HttpMessageConverter接口:消息转换器。
功能:定义了java转为json,xml等数据格式的方法。这个接口有很多的实现类。
这些实现类完成 java对象到json, java对象到xml,java对象到二进制数据的转换
下面的两个方法是控制器类把结果输出给浏览器时使用的:
boolean canWrite(Class<?> var1, @Nullable MediaType var2);
void write(T var1, @Nullable MediaType var2, HttpOutputMessage var3)
例如处理器方法
@RequestMapping(value = "/returnString.do")
public Student doReturnView2(HttpServletRequest request,String name, Integer age){
Student student = new Student();
student.setName("lisi");
student.setAge(20);
return student;
}
1)canWrite作用检查处理器方法的返回值,能不能转为var2表示的数据格式。
检查student(lisi,20)能不能转为var2表示的数据格式。如果检查能转为json,canWrite返回true
MediaType:表示数格式的, 例如json, xml等等
2)write:把处理器方法的返回值对象,调用jackson中的ObjectMapper转为json字符串。
json = om.writeValueAsString(student);
2. @ResponseBody注解
放在处理器方法的上面, 通过HttpServletResponse输出数据,响应ajax请求的。
PrintWriter pw = response.getWriter();
pw.println(json);
pw.flush();
pw.close();
(1)加入依赖
由于返回 Object 数据,一般都是将数据转化为了 JSON 对象后传递给浏览器页面的。
而这个由 Object 转换为 JSON,是由 Jackson 工具完成的。所以需要导入 Jackson 的相关 Jar 包。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency
(2)声明注解驱动(约束文件的地址是以mvc结尾)
将 Object 数据转化为 JSON 数据,需要由消息转换器 HttpMessageConverter 完成。而转换器的开启,需要由mvc:annotation-driven
完成。
SpringMVC 使用消息转换器实现请求数据和对象,处理器方法返回对象和响应输出之间的自动转换 。
当 Spring 容器进行初始化过程中,在mvc:annotation-driven
处创建注解驱动时,默认创建了七个HttpMessageConverter 对象。
也就是说,我们注册mvc:annotation-driven
,就是为了让容器为我们创建 HttpMessageConverter 对象。
在springmvc.xml中:
<!--注册mvc注解驱动-->
<mvc:annotation-driven />
(3)在控制器方法中添加注解@ResponseBody,将数据通过response对象返回
返回值类型也可以是一个List集合,这样框架会自动将结果数据转化成json数组。
顺序与List添加元素顺序相同。
当返回值类型是String的控制器方法添加了ResponseBody注解,此字符串不会作为视图处理,而是结果数据。
如果包含中文,会出现乱码,在RequestMapping中添加属性produces=“text/plain;charset=utf-8”。
参考代码:
/**
* 处理器方法返回一个Student,通过框架转为json,响应ajax请求
* @ResponseBody:
* 作用:把处理器方法返回对象转为json后,通过HttpServletResponse输出给浏览器。
* 位置:方法的定义上面。 和其它注解没有顺序的关系。
* 返回对象框架的处理流程:
* 1. 框架会把返回Student类型,调用框架的中ArrayList<HttpMessageConverter>中每个类的canWrite()方法
* 检查那个HttpMessageConverter接口的实现类能处理Student类型的数据--MappingJackson2HttpMessageConverter
*
* 2.框架会调用实现类的write(), MappingJackson2HttpMessageConverter的write()方法
* 把李四同学的student对象转为json, 调用Jackson的ObjectMapper实现转为json
* contentType: application/json;charset=utf-8
*
* 3.框架会调用@ResponseBody把2的结果数据输出到浏览器, ajax请求处理完成
*/
@RequestMapping(value = "/returnStudentJson.do")
@ResponseBody
public Student doStudentJsonObject(String name, Integer age) {
//调用service,获取请求结果数据 , Student对象表示结果数据
Student student = new Student();
student.setName("李四同学");
student.setAge(20);
return student; // 会被框架转为json
}
/**
* 处理器方法返回List<Student>
* 返回对象框架的处理流程:
* 1. 框架会把返回List<Student>类型,调用框架的中ArrayList<HttpMessageConverter>中每个类的canWrite()方法
* 检查那个HttpMessageConverter接口的实现类能处理Student类型的数据--MappingJackson2HttpMessageConverter
*
* 2.框架会调用实现类的write(), MappingJackson2HttpMessageConverter的write()方法
* 把李四同学的student对象转为json, 调用Jackson的ObjectMapper实现转为json array
* contentType: application/json;charset=utf-8
*
* 3.框架会调用@ResponseBody把2的结果数据输出到浏览器, ajax请求处理完成
*/
@RequestMapping(value = "/returnStudentJsonArray.do")
@ResponseBody
public List<Student> doStudentJsonObjectArray(String name, Integer age) {
List<Student> list = new ArrayList<>();
//调用service,获取请求结果数据 , Student对象表示结果数据
Student student = new Student();
student.setName("李四同学");
student.setAge(20);
list.add(student);
student = new Student();
student.setName("张三");
student.setAge(28);
list.add(student);
return list;
}
/**
* 处理器方法返回的是String , String表示数据的,不是视图。
* 区分返回值String是数据,还是视图,看有没有@ResponseBody注解
* 如果有@ResponseBody注解,返回String就是数据,反之就是视图
*
* 默认使用“text/plain;charset=ISO-8859-1”作为contentType,导致中文有乱码,
* 解决方案:给RequestMapping增加一个属性 produces, 使用这个属性指定新的contentType.
* 返回对象框架的处理流程:
* 1. 框架会把返回String类型,调用框架的中ArrayList<HttpMessageConverter>中每个类的canWrite()方法
* 检查那个HttpMessageConverter接口的实现类能处理String类型的数据--StringHttpMessageConverter
*
* 2.框架会调用实现类的write(), StringHttpMessageConverter的write()方法
* 把字符按照指定的编码处理 text/plain;charset=ISO-8859-1
*
* 3.框架会调用@ResponseBody把2的结果数据输出到浏览器, ajax请求处理完成
*/
@RequestMapping(value = "/returnStringData.do",produces = "text/plain;charset=utf-8")
@ResponseBody
public String doStringData(String name,Integer age){
return "Hello SpringMVC 返回对象,表示数据";
}
解读<url-pattern>
标签
tomcat是如何处理静态资源的请求的呢?
存在一个默认Servlet,在conf/web.xml下:
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
作用:The default servlet for all web applications, that serves static resources. It processes all requests that are not mapped to other servlets with servlet mappings (defined either here or in your own web.xml file).
注意url-pattern的内容是:/ 。
它的功能就是map all servlets that are not mapped to other servlets with servlet mappings 。
在SpringMVC中,中央调度器处理各种请求,因此需要写各种url-pattern,如果只写/会很方便。但是会造成静态资源无法访问。
在中央调度器的url-pattern使用 / ,如何解决静态资源无法访问的问题?
方法一
在springmvc.xml配置文件中添加:
<mvc:default-servlet-handler/>
其原理是创建DefaultServletHttpRequestHandler对象,类似于控制器,它能将静态资源请求转发给tomcat的defaultServlet。(requestDispatcher.forward)
创建ResourcehttpRequestHandler对象来处理静态资源的访问,不依赖tomcat,
方法二:(掌握)
在 Spring3.0 版本后,Spring 定义了专门用于处理静态资源访问请求的处理器 ResourceHttpRequestHandler。
并且添加了mvc:resources
标签,专门用于解决静态资源无法访问问题。需要在 springmvc 配置文件中添加如下形式的配置:
<mvc:resources mapping="images/**" location="/images/"/>
<mvc:resources mapping="js/**" location="/js/"/>
<mvc:resources mapping="html/**" location="/html/"/>
location 表示静态资源所在目录。当然,目录不要使用/WEB-INF/及其子目录。
mapping 表示对该资源的请求 。注意,后面是两个星号**。
注意:两种方式均需要在springmvc配置文件中添加注解驱动标签,解决冲突。
<!--注册mvc注解驱动-->
<mvc:annotation-driven />
SSM整合开发
SSM 编程,即 SpringMVC + Spring + MyBatis 整合,是当前最为流行的 JavaEE 开发技术架构。
其实 SSM 整合的实质,仅仅就是将 MyBatis整合入 Spring。
因为 SpringMVC原本就是 Spring 的一部分,不用专门整合。
SSM 整合的实现方式可分为两种:基于 XML 配置方式,基于注解方式。
概述
SSM:SpringMVC + Spring + MyBatis.
SpringMVC:视图层,界面层,负责接收请求,显示处理结果的。
Spring:业务层,管理service,dao,工具类对象的。
MyBatis:持久层, 访问数据库的
用户发起请求--SpringMVC接收--Spring中的Service对象--MyBatis处理数据
SSM整合也叫做SSI (IBatis也就是mybatis的前身), 整合中有容器。
1.第一个容器SpringMVC容器, 管理Controller控制器对象的。
2.第二个容器Spring容器,管理Service,Dao,工具类对象的
我们要做的把使用的对象交给合适的容器创建,管理。把Controller还有web开发的相关对象
交给springmvc容器, 这些web用的对象写在springmvc配置文件中
service,dao对象定义在spring的配置文件中,让spring管理这些对象。
springmvc容器和spring容器是有关系的,关系已经确定好了
springmvc容器是spring容器的子容器, 类似java中的继承。子可以访问父的内容
在子容器中的Controller可以访问父容器中的Service对象, 就可以实现controller使用service对象
实现步骤:
0.使用springdb的mysql库, 表使用student(id auto_increment, name, age)
1.新建maven web项目
2.加入依赖
springmvc,spring,mybatis三个框架的依赖,jackson依赖,mysql驱动,druid连接池
jsp,servlet依赖
3.写web.xml
1)注册DispatcherServlet ,目的:1.创建springmvc容器对象,才能创建Controller类对象。
2.创建的是Servlet,才能接受用户的请求。
2)注册spring的监听器:ContextLoaderListener,目的:创建spring的容器对象,才能创建service,dao等对象。
3)注册字符集过滤器,解决post请求乱码的问题
4.创建包, Controller包, service ,dao,实体类包名创建好
5.写springmvc,spring,mybatis的配置文件
1)springmvc配置文件
2)spring配置文件
3)mybatis主配置文件
4)数据库的属性配置文件
6.写代码, dao接口和mapper文件, service和实现类,controller, 实体类。
7.写jsp页面
搭建 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.kwxy</groupId>
<artifactId>my_ssm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--servlet依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jsp依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2.1-b03</version>
<scope>provided</scope>
</dependency>
<!-- springmvc依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!-- spring事务依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!-- json依赖 -->
<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>
<!-- mybatis和spring整合的依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!--数据库驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
<!--数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
</dependencies>
<build>
<!--资源插件-->
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置 web.xml
(1)注册 ContextLoaderListener 监听器
注册 ServletContext 监听器的实现类 ContextLoaderListener,用于创建 Spring 容器及将创建好的 Spring 容器对象放入到 ServletContext 的作用域中。
<!--注册spring的监听器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
(2)注册字符集过滤器
注册字符集过滤器,用于解决请求参数中携带中文时产生乱码问题。
<!--注册字符集过滤器-->
<filter>
<filter-name>characterEncodingFilter</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>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(3)配置中央调度器
配置中央调度器时需要注意,SpringMVC的配置文件名与其它 Spring配置文件名不相同。
这样做的目的是 Spring 容器创建管理 Spring 配置文件中的 bean, SpringMVC 容器中负责视图层 bean 的初始化。
<!--注册中央调度器-->
<servlet>
<servlet-name>myweb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/dispatcherServlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myweb</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
SSM 整合注解开发
建表Student(包含id,name,age)
新建Web工程
定义包,组织程序的结构
创建相应层的包:
(1)com.kwxy.controller
(2)com.kwxy.service
(3)com.kwxy.dao
(4)com.kwxy.domain
resources下创建配置文件:
(1)mybatis.xml (mybatis配置文件)
(2)jdbc.properties (jdbc配置文件)
(3)dispatcherServlet.xml (springmvc配置文件)
(4)applicationContext.xml (spring配置文件)
webapp下创建jsp文件:
addStudent.jsp、index.jsp、listStudent.jsp
webapp下创建目录:
images目录、js目录
WEB-INF下创建jsp目录,在jsp目录中创建result.jsp
编写配置文件
jdbc 属性配置文件 jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.username=root
jdbc.password=root
Spring 配置文件 applicationContext.xml
<!--spring配置文件: 声明service,dao,工具类等对象-->
<context:property-placeholder location="classpath:conf/jdbc.properties" />
<!--声明数据源,连接数据库-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!--SqlSessionFactoryBean创建SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:conf/mybatis.xml" />
</bean>
<!--声明mybatis的扫描器,创建dao对象-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<property name="basePackage" value="com.kwxy.dao" />
</bean>
<!--声明service的注解@Service所在的包名位置-->
<context:component-scan base-package="com.kwxy.service" />
<!--事务配置:注解的配置, aspectj的配置-->
Springmvc 配置文件:dispatcherServlet.xml
<!--springmvc配置文件, 声明controller和其它web相关的对象-->
<context:component-scan base-package="com.kwxy.controller" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<mvc:annotation-driven />
<!--
1. 响应ajax请求,返回json
2. 解决静态资源访问问题。
-->
mybatis.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>
<!--设置别名-->
<typeAliases>
<!--name:实体类所在的包名(不是实体类的包名也可以)-->
<package name="com.kwxy.domain"/>
</typeAliases>
<!-- sql mapper(sql映射文件)的位置-->
<mappers>
<!--
name:是包名, 这个包中的所有mapper.xml一次都能加载
使用package的要求:
1. mapper文件名称和dao接口名必须完全一样,包括大小写
2. mapper文件和dao接口必须在同一目录
-->
<package name="com.kwxy.dao"/>
</mappers>
</configuration>
web.xml配置见上方
1)注册 ContextLoaderListener
2)注册 DisatcherServlet
3)注册字符集过滤器
4)同时创建 Spring 的配置文件和 SpringMVC 的配置文件
实体类 Student
package com.kwxy.domain;
public class Student {
private Integer id;
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
Dao接口和sql映射文件
StudentDao.java
package com.kwxy.dao;
import com.kwxy.domain.Student;
import java.util.List;
public interface StudentDao {
int insertStudent(Student student);
List<Student> selectStudents();
}
StudentDao.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kwxy.dao.StudentDao">
<select id="selectStudents" resultType="Student">
select id,name,age from student order by id desc
</select>
<insert id="insertStudent">
insert into student(name,age) values(#{name},#{age})
</insert>
</mapper>
Service 接口和实现类
StudentService.java
package com.kwxy.service;
import com.kwxy.domain.Student;
import java.util.List;
public interface StudentService {
int addStudent(Student student);
List<Student> findStudents();
}
StudentServiceImpl.java
package com.kwxy.service.impl;
import com.kwxy.dao.StudentDao;
import com.kwxy.domain.Student;
import com.kwxy.service.StudentService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class StudentServiceImpl implements StudentService {
//引用类型自动注入@Autowired, @Resource
@Resource
private StudentDao studentDao;
@Override
public int addStudent(Student student) {
int nums = studentDao.insertStudent(student);
return nums;
}
@Override
public List<Student> findStudents() {
return studentDao.selectStudents();
}
}
处理器定义
StudentController.java
package com.kwxy.controller;
import com.kwxy.domain.Student;
import com.kwxy.service.StudentService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
import java.util.List;
@Controller
@RequestMapping("/student")
public class StudentController {
@Resource
private StudentService service;
//注册学生
@RequestMapping("/addStudent.do")
public ModelAndView addStudent(Student student){
ModelAndView mv = new ModelAndView();
String tips = "注册失败";
//调用service处理student
int nums = service.addStudent(student);
if( nums > 0 ){
//注册成功
tips = "学生【" + student.getName() + "】注册成功";
}
//添加数据
mv.addObject("tips",tips);
//指定结果页面
mv.setViewName("result");
return mv;
}
//处理查询,响应ajax
@RequestMapping("/queryStudent.do")
@ResponseBody
public List<Student> queryStudent(){
//参数检查, 简单的数据处理
List<Student> students = service.findStudents();
return students;
}
}
定义视图-首页文件—index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/";
%>
<html>
<head>
<title>功能入口</title>
<base href="<%=basePath%>" />
</head>
<body>
<div align="center">
<p>SSM整合的例子</p>
<img src="images/ssm.jpg" />
<table>
<tr>
<td><a href="addStudent.jsp"> 注册学生</a></td>
</tr>
<tr>
<td><a href="listStudent.jsp">浏览学生</a></td>
</tr>
</table>
</div>
</body>
</html>
注册学生页面—-addStudent.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/";
%>
<html>
<head>
<title>注册学生</title>
<base href="<%=basePath%>" />
</head>
<body>
<div align="center">
<form action="student/addStudent.do" method="post">
<table>
<tr>
<td>姓名:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>年龄:</td>
<td><input type="text" name="age"></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" value="注册"></td>
</tr>
</table>
</form>
</div>
</body>
</html>
浏览学生页面—-listStudent.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/";
%>
<html>
<head>
<title>查询学生ajax</title>
<base href="<%=basePath%>" />
<script type="text/javascript" src="js/jquery-3.4.1.js"></script>
<script type="text/javascript">
$(function(){
//在当前页面dom对象加载后,执行loadStudentData()
loadStudentData();
$("#btnLoader").click(function(){
//loadStudentData();
alert($("#country > option:selected").val());
alert($("#country > option:selected").text());
})
})
function loadStudentData(){
$.ajax({
url:"student/queryStudent.do",
type:"get",
dataType:"json",
success:function(data){
//清除旧的数据
$("#info").html("");
//增加新的数据
$.each(data,function(i,n){
$("#info").append("<tr>")
.append("<td>"+n.id+"</td>")
.append("<td>"+n.name+"</td>")
.append("<td>"+n.age+"</td>")
.append("</tr>")
})
}
})
}
</script>
</head>
<body>
<div align="center">
<table>
<thead>
<tr>
<td>学号</td>
<td>姓名</td>
<td>年龄</td>
</tr>
</thead>
<tbody id="info">
</tbody>
</table>
<input type="button" id="btnLoader" value="查询数据">
<select id="country">
<option value="1">中国</option>
<option value="2">俄罗斯</option>
<option value="3">西班牙</option>
</select>
</div>
</body>
</html>
注册结果页面—-result.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>注册结果</title>
</head>
<body>
result.jsp 结果页面,注册结果: ${tips}
</body>
</html>
SpringMVC核心技术
forward:表示转发 redirect:表示重定向
forward和redirect都是关键字, 有一个共同的特点不和视图解析器一同工作
扩展:
forward和redirect他们都可以访问 视图文件,比如某个jsp ,html
forward:/hello.jsp forward:/main.html
forward和redirect他们都可以访问其它的controller
forward:/some.do , redirect:/other.do
处理器方法可以返回ModelAndView, String , void 都可以使用forward,redirect
请求转发
使用规则:
moduleAndView对象.setViewName("forward:转发目标完整路径");
//forward是关键字
特点:不与视图解析器一同使用用途:可以转发至视图解析器指定的资源以外的资源。
参考代码:
/**
* 处理器方法返回ModelAndView,实现转发forward
* 语法:setViewName("forward:视图文件完整路径")
* forward特点: 不和视图解析器一同使用,就当项目中没有视图解析器
*/
@RequestMapping(value = "/doForward.do")
public ModelAndView doSome(){
//处理some.do请求了。 相当于service调用处理完成了。
ModelAndView mv = new ModelAndView();
mv.addObject("msg","欢迎使用springmvc做web开发");
mv.addObject("fun","执行的是doSome方法");
//显示转发
//mv.setViewName("forward:/WEB-INF/view/show.jsp");
mv.setViewName("forward:/hello.jsp");
return mv;
}
重定向
使用规则:
moduleAndView对象.setViewName("redirect:转发目标完整路径");
//redirect是关键字
特点:不与视图解析器一同使用。本质是两次访问,不能访问WEB-INF目录下的资源传参:由于是两次不同的请求,因此不能通过getAttribute获得参数。
当我们向ModelAndView对象添加数据(addObject方法)以后,这些数据会在发送第二次请求时以get方式呈现在url后(?参数名=参数值&…)
参考代码:
/**
* 处理器方法返回ModelAndView,实现重定向redirect
* 语法:setViewName("redirect:视图完整路径")
* redirect特点: 不和视图解析器一同使用,就当项目中没有视图解析器
*
* 框架对重定向的操作:
* 1.框架会把Model中的简单类型的数据,转为string使用,作为hello.jsp的get请求参数使用。
* 目的是在 doRedirect.do 和 hello.jsp 两次请求之间传递数据
*
* 2.在目标hello.jsp页面可以使用参数集合对象 ${param}获取请求参数值
* ${param.myname}
*
* 3.重定向不能访问/WEB-INF资源
*/
@RequestMapping(value = "/doRedirect.do")
public ModelAndView doWithRedirect(String name,Integer age){
//处理some.do请求了。 相当于service调用处理完成了。
ModelAndView mv = new ModelAndView();
//数据放入到 request作用域
mv.addObject("myname",name);
mv.addObject("myage",age);
//重定向
//mv.setViewName("redirect:/hello.jsp");
//http://localhost:8080/ch08_forard_redirect/hello.jsp?myname=lisi&myage=22
//重定向不能访问/WEB-INF资源
mv.setViewName("redirect:/WEB-INF/view/show.jsp");
return mv;
}
异常处理
SpringMVC处理异常使用的是AOP的思想,其目的是将异常处理的代码与业务代码分开,达到解耦合的目的。
(1)创建自定义的异常
自定义的异常类需要继承java.lang.Exception,并至少给出无参构造器和带有String参数的构造器。
例如:
package com.kwxy.exception;
public class MyUserException extends Exception {
public MyUserException() {
super();
}
public MyUserException(String message) {
super(message);
}
}
package com.kwxy.exception;
//当年龄有问题时,抛出的异常
public class AgeException extends MyUserException {
public AgeException() {
super();
}
public AgeException(String message) {
super(message);
}
}
package com.kwxy.exception;
//表示当用户的姓名有异常,抛出NameException
public class NameException extends MyUserException {
public NameException() {
super();
}
public NameException(String message) {
super(message);
}
}
(2)在Controller中向上抛出这些异常
/**
* @RequestMapping:
* value : 所有请求地址的公共部分,叫做模块名称
* 位置: 放在类的上面
*/
@Controller
public class MyController {
@RequestMapping(value = "/some.do")
public ModelAndView doSome(String name,Integer age) throws MyUserException {
//处理some.do请求了。 相当于service调用处理完成了。
ModelAndView mv = new ModelAndView();
//try {
//根据请求参数抛出异常
if (!"zs".equals(name)) {
throw new NameException("姓名不正确!!!");
}
if (age == null || age > 80) {
throw new AgeException("年龄比较大!!!");
}
//}catch(Exception e){
// e.printStackTrace();
//}
mv.addObject("myname",name);
mv.addObject("myage",age);
mv.setViewName("show");
return mv;
}
}
(3)定义全局异常处理类
在类前添加注解:@controllerAdvice
在类中给出异常处理的切面方法。
这些方法的定义规则与第二章中控制器方法的定义规则相同,还可以添加一个形参Exception表示要处理的异常对象。
在方法前添加注解:@ExceptionHandler 其value属性类型是Class,表示要处理的异常类型(value=异常类名.class)。
如果没有value属性,则此方法用来处理未指定的异常类型。
package com.kwxy.handler;
import com.kwxy.exception.AgeException;
import com.kwxy.exception.NameException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
/**
* @ControllerAdvice : 控制器增强(也就是说给控制器类增加功能--异常处理功能)
* 位置:在类的上面。
* 特点:必须让框架知道这个注解所在的包名,需要在springmvc配置文件声明组件扫描器。
* 指定@ControllerAdvice所在的包名
*/
@ControllerAdvice
public class GlobalExceptionHandler {
//定义方法,处理发生的异常
/*
处理异常的方法和控制器方法的定义一样, 可以有多个参数,可以有ModelAndView,
String, void,对象类型的返回值
形参:Exception,表示Controller中抛出的异常对象。
通过形参可以获取发生的异常信息。
@ExceptionHandler(异常的class):表示异常的类型,当发生此类型异常时,
由当前方法处理
*/
@ExceptionHandler(value = NameException.class)
public ModelAndView doNameException(Exception exception){
//处理NameException的异常。
/*
异常发生处理逻辑:
1.需要把异常记录下来, 记录到数据库,日志文件。
记录日志发生的时间,哪个方法发生的,异常错误内容。
2.发送通知,把异常的信息通过邮件,短信,微信发送给相关人员。
3.给用户友好的提示。
*/
ModelAndView mv = new ModelAndView();
mv.addObject("msg","姓名必须是zs,其它用户不能访问");
mv.addObject("ex",exception);
mv.setViewName("nameError");
return mv;
}
//处理AgeException
@ExceptionHandler(value = AgeException.class)
public ModelAndView doAgeException(Exception exception){
//处理AgeException的异常。
/*
异常发生处理逻辑:
1.需要把异常记录下来, 记录到数据库,日志文件。
记录日志发生的时间,哪个方法发生的,异常错误内容。
2.发送通知,把异常的信息通过邮件,短信,微信发送给相关人员。
3.给用户友好的提示。
*/
ModelAndView mv = new ModelAndView();
mv.addObject("msg","你的年龄不能大于80");
mv.addObject("ex",exception);
mv.setViewName("ageError");
return mv;
}
//处理其它异常, NameException, AgeException以外,不知类型的异常
@ExceptionHandler
public ModelAndView doOtherException(Exception exception){
//处理其它异常
ModelAndView mv = new ModelAndView();
mv.addObject("msg","你的年龄不能大于80");
mv.addObject("ex",exception);
mv.setViewName("defaultError");
return mv;
}
}
(4)在springmvc配置文件中添加标签扫描器与注解驱动
<!--处理需要的两步-->
<context:component-scan base-package="com.kwxy.handler" />
<mvc:annotation-driven />
拦截器
SpringMVC 中的 Interceptor 拦截器是非常重要和相当有用的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。
其拦截的时间点在“处理器映射器根据用户提交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器,在处理器适配器执行处理器之前”。
当然,在处理器映射器映射出所要执行的处理器类时, 已经将拦截器与处理器组合为了一个处理器执行链,并返回给了中央调度器。
一个拦截器的执行
自定义拦截器
package com.kwxy.handler;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
//拦截器类:拦截用户的请求。
public class MyInterceptor implements HandlerInterceptor {
private long btime = 0;
/*
* preHandle叫做预处理方法。
* 重要:是整个项目的入口,门户。 当preHandle返回true 请求可以被处理。
* preHandle返回false,请求到此方法就截止。
*
* 参数:
* Object handler : 被拦截的控制器对象
* 返回值boolean
* true:请求是通过了拦截器的验证,可以执行处理器方法。
* 拦截器的MyInterceptor的preHandle()
=====执行MyController中的doSome方法=====
拦截器的MyInterceptor的postHandle()
拦截器的MyInterceptor的afterCompletion()
*
* false:请求没有通过拦截器的验证,请求到达拦截器就截止了。 请求没有被处理
* 拦截器的MyInterceptor的preHandle()
*
*
* 特点:
* 1.方法在控制器方法(MyController的doSome)之前先执行的。
* 用户的请求首先到达此方法
*
* 2.在这个 方法中可以获取请求的信息, 验证请求是否符合要求。
* 可以验证用户是否登录, 验证用户是否有权限访问某个连接地址(url)。
* 如果验证失败,可以截断请求,请求不能被处理。
* 如果验证成功,可以放行请求,此时控制器方法才能执行。
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
btime = System.currentTimeMillis();
System.out.println("拦截器的MyInterceptor的preHandle()");
return true;
}
/*
postHandle:后处理方法。
参数:
Object handler:被拦截的处理器对象MyController
ModelAndView mv:处理器方法的返回值
特点:
1.在处理器方法之后执行的(MyController.doSome())
2.能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的
数据和视图,可以影响到最后的执行结果。
3.主要是对原来的执行结果做二次修正,
ModelAndView mv = MyController.doSome();
postHandle(request,response,handler,mv);
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler, ModelAndView mv) throws Exception {
System.out.println("拦截器的MyInterceptor的postHandle()");
}
}
/*
afterCompletion:最后执行的方法
参数
Object handler:被拦截器的处理器对象
Exception ex:程序中发生的异常
特点:
1.在请求处理完成后执行的。框架中规定是当你的视图处理完成后,对视图执行了forward。就认为请求处理完成。
2.一般做资源回收工作的, 程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收。
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("拦截器的MyInterceptor的afterCompletion()");
}
}
自定义拦截器,需要实现 HandlerInterceptor 接口。而该接口中含有三个方法:
➢ **preHandle(request,response, Object handler)**:
该方法在处理器方法执行之前执行。其返回值为 boolean,若为 true,则紧接着会执行处理器方
法,且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行。
➢ **postHandle(request,response, Object handler,modelAndView)**:
该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。
由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修
改处理器方法的处理结果数据,且可以修改跳转方向。
➢ **afterCompletion(request,response, Object handler, Exception ex)**:
当 preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有
工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此
时对 ModelAndView 再操作也对响应无济于事。
afterCompletion 最后执行的方法,清除资源,例如在 Controller 方法中加入数据
编写控制器:
package com.kwxy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* @RequestMapping:
* value : 所有请求地址的公共部分,叫做模块名称
* 位置: 放在类的上面
*/
@Controller
public class MyController {
@RequestMapping(value = "/some.do")
public ModelAndView doSome(String name,Integer age) {
System.out.println("=====执行MyController中的doSome方法=====");
//处理some.do请求了。 相当于service调用处理完成了。
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
mv.setViewName("show");
return mv;
}
}
在springmvc.xml中声明拦截器:
<!--声明拦截器: 拦截器可以有0或多个-->
<mvc:interceptors>
<!--声明第一个拦截器-->
<mvc:interceptor>
<!--指定拦截的请求uri地址
path:就是uri地址,可以使用通配符 **
** : 表示任意的字符,文件或者多级目录和目录中的文件
http://localhost:8080/myweb/user/listUser.do
http://localhost:8080/myweb/student/addStudent.do
-->
<mvc:mapping path="/**"/>
<!--声明拦截器对象-->
<bean class="com.kwxy.handler.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
原文始发于微信公众号(程序员阿晶):你了解SpringMVC吗
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/19676.html