SpringMVC
第一章 SpringMVC概述
1.1 SpringMVC简介
springMVC是基于spring的一个框架,实际上就是spring的一个模块,专门做web开发的。理解是servlet的一个升级。
web开发底层是servlet,框架是在servlet基础上面加入一些功能,让你的web开发更方便。
web开发底层是servlet,springmvc中一个对象是servlet:DispatherServlet
DispatherServlet:负责接收用户的所有请求,用户吧请求给了DispatherServlet,之后DispatherServlet吧请求转发给我们的Controller对象,最后是Controller对象处理请求。
1.2 SpringMVC 优点
1、基于MVC架构
基于 MVC 架构,功能分工明确。解耦合。
2、容易理解,上手快;使用简单
就可以开发一个注解的 SpringMVC 项目,SpringMVC 也是轻量级的,jar 很小。不依赖的 特定的接口和类。
3、 作 为 Spring 框 架 一 部 分 , 能 够 使 用 Spring 的 IoC 和 Aop 。
方 便 整 合 Strtus,MyBatis,Hiberate,JPA 等其他框架。
4、SpringMVC 强化注解的使用,在控制器,Service,Dao 都可以使用注解。方便灵活。
使用@Controller 创建处理器对象,@Service 创建业务对象,@Autowired 或者@Resource 在控制器类中注入 Service, Service 类中注入 Dao。
1.3 入门案例
需求:用户在页面发起一个请求,请求交给springmvc的控制器对象,
并显示请求的处理结果(在结果页面显示一个欢迎语句)。
1.3.1 实现步骤
1、新建web Maven工程
2、加入依赖
spring-webmvc 依赖,间接吧spring的依赖都加入到项目中
jsp,servlet依赖
3、重点:在web.xml中注册springmvc框架的核心对象DispatcherServlet。
1)DispatcherServlet叫做中央调度器,是一个servlet,它的父类是继承HttpServlet
2)DispatcherServlet也叫做前端控制器,(front controller)
3)DispatcherServlet负责接收用户提交的请求,调用其他的控制器对象,并把请求的处理结果显示给用户。
4、创建一个发起请求的页面 index.jsp
5、创建控制器类
1)在类的上面加入@Controller注解,创建对象,并放入到spring容器中。
2)在类中的方法上面加入@Requestmapping注解。
6、创建一个作为结果的jsp,显示请求的处理结果。
7、创建springmvc的配置文件(spring的配置文件一样)
1)声明组件扫描器,指定@Controller注解所在的包名。
2)声明视图解析器,帮助处理视图的。
1.3.2 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()把得到ModerlAndView进行处理,转发到show.jsp。
1.3.3 Springmvc 执行过程源代码分析
1、tomcat启动,创建容器的过程
通过load-on-start标签指定的1,创建DispatcherServlet对象。
DispatcherServlet它的父类是继承HttpServlet的,它是一个servlet,在被创建时,会执行init()方法。
在init()方法中
//创建容器,读取配置文件
WebApplicationContext context = new ClassPathXmlApplicationContext("springmvc.xml");
//把容器对象放入ServletContext中
getServletContext().setAttribute(key, context)
上面创建容器作用:创建@Controller注解所在的类的对象,创建MyController对象。
这个对象放入到springmvc的容器中,容器是map,类似map.put("myController",MyController对象)
2、请求的处理流程
1)执行servlet的service()方法
protected void service(HttpServletRequest request, HttpServletResponse response)
protected void doService(HttpServletRequest request, HttpServletResponse response)
DispatcherServlet.doDispatch(request, response){
调用MyController的do.some()方法
}
3、流程图
第二章 SpringMVC 注解式开发
2.1 @RequestMapping 定义请求规则
2.1.1 指定模块名称
一个@Controller 所注解的类中,可以定义多个处理器方法。当然,不同的处理器方法
所匹配的 URI 是不同的。这些不同的 URI 被指定在注解于方法之上的@RequestMapping 的
value 属性中。但若这些请求具有相同的 URI 部分,则这些相同的 URI,可以被抽取到注解在
类之上的@RequestMapping 的 value 属性中。此时的这个 URI 表示模块的名称。URI 的请求
是相对于 Web 的根目录。
示例:
@RequestMapping(value = "/test")
public class MyController {}
//value:所有请求地址的公共部分,叫做模块名称
//位置:放在类的上面
2.1.2 对请求提交方式的定义
对于@RequestMapping,其有一个属性 method,用于对被注解方法所处理请求的提交
方式进行限制,即只有满足该 method 属性指定的提交方式的请求,才会执行该被注解方法。
Method 属性的取值为 RequestMethod 枚举常量。常用的为 RequestMethod.GET 与
RequestMethod.POST,分别表示提交方式的匹配规则为 GET 与 POST 提交。
如果不指定用哪一种请求方式,则表示都可以接收。
示例
//Post请求方式
@RequestMapping(value = {"/other.do"}, method = RequestMethod.POST)
public ModelAndView doOther() {}
//get请求方式
@RequestMapping(value = "/some.do", method = RequestMethod.GET)
public ModelAndView doSome() {
2.2 处理器方法的参数
处理器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,即程序 员可在方法内直接使用。
➢ HttpServletRequest
➢ HttpServletResponse
➢ HttpSession
➢ 请求中所携带的请求参数
2.2.1 逐个接收
只要保证请求参数名与该请求处理方法的参数名相同即可。
逐个接收请求参数:
* 要求:处理器方法的形参名和请求中参数名必须一致
* 同名的请求参数赋值给同名的形参,于Controller中方法形参的位置无关。
框架接收请求参数
1、使用request对象接收请求参数
String strName = request.getParameter("name");
String strAge = request.getParameter("age");
2、springmvc框架通过DispatcherServlet 调用MyController的doSome()方法
调用方法时,按名称对应,把接收的参数赋值给形参
doSome(StrName, Integer.parseInt(strAge));
框架会提供类型转换得到功能,能把String转为int,long,double,float等类型。
400状态码是客户端错误,表示提交的请求参数过程中,发生了问题。
Controller方法代码
@RequestMapping(value = {"/receiveProperty.do"}, method = RequestMethod.GET)
public ModelAndView doOther(String name, Integer age) {
System.out.println("name = " + name+", age = "+age);
ModelAndView mv = new ModelAndView();
mv.addObject("name", name);
mv.addObject("age", age);
mv.setViewName("other");
return mv;
}
other.jsp
<body>
<h3>/WEB-INF/view/show.jsp 从request作用域中获取数据</h3>
<h3>myName数据:${name}</h3>
<h3>myAge数据:${age}</h3>
</body>
2.2.2 请求参数中文乱码问题
在提交请求参数时,get请求方式中文没有乱码。
使用POST方式提交请求时,中文有乱码,需要使用过滤器处理乱码问题。(可以自定义,也可以用框架)。
web.xml中注册声明过滤器
<!-- 注册声明过滤器,解决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>
2.2.3 源码分析
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//表示值"utf-8"
String encoding = this.getEncoding();
if (encoding != null) {
//isForceRequestEncoding() = true
if (this.isForceRequestEncoding() || request.getCharacterEncoding() == null) {
request.setCharacterEncoding(encoding);
}
// isForceResponseEncoding() = true
if (this.isForceResponseEncoding()) {
response.setCharacterEncoding(encoding);
}
}
filterChain.doFilter(request, response);
}
2.2.4 请求中参数名形参名不一致
@RequestParam:解决请求中参数名和形参名不一致的问题。
属性:
1)value,请求中的参数名称。
2)required 是一个Boolean类型,默认时true,
true:表示请求中必须包含此参数。
位置:在处理器方法的形参定义的前面。
@RequestMapping(value = {"/receiveParam.do"}, method = RequestMethod.POST)
public ModelAndView receiveParam(@RequestParam("Pname",required = false) String name, @RequestParam("Page") Integer age) {}
2.2.5 对象参数接收
将处理器方法的参数定义为一个对象,只要保证请求参数名与这个对象的属性同名即可。 项目:receiveParameters-object。在 receiveParameters-property 基础上修改。
1、处理器方法形参是Java对象,这个对象的属性名和请求中的参数名一样的
2、框架会创建形参的Java对象,给属性赋值。请求中的参数是name,框架会调用setName()
定义student类
/**
* 保存请求参数值的一个普通类
*/
public class Student {
// 属性名和请求中参数名一样
private String name;
private Integer age;
此处省略了set,get,以及无参数构造方法
...
}
前端页面 param.jsp
<p>使用Java对象接收请求参数</p>
<form action="test/receiveObject.do" method="post">
姓名:<input type="text" name="name"><br/>
年龄:<input type="text" name="age"><br/>
<input type="submit" value="提交参数">
</form>
Controller中的方法
/**
* 处理器方法形参是Java对象,这个对象的属性名和请求中的参数名一样的
* 框架会创建形参的Java对象,给属性赋值。请求中的参数是name,框架会调用setName()
*
* @return
*/
@RequestMapping(value = {"/receiveObject.do"}, method = RequestMethod.POST)
public ModelAndView receiveObject(Student stu, School school) {
System.out.println("stu = " + stu);
System.out.println("school = " + school);
ModelAndView mv = new ModelAndView();
mv.addObject("student", stu);
mv.setViewName("param");
return mv;
}
注意:
//1、如果传入多个形参都是对象类型,且两个对象之间有相同的属性名称,那么框架会对其两个对象的相同属性都进行赋值。
public ModelAndView receiveObject(Student stu, School school) {}
//Student类和School类中有相同的属性name,则框架会将其都赋值。
2.3 处理器方法的返回值
使用@Controller 注解的处理器的处理器方法,
其返回值常用的有四种类型:
➢ 第一种:ModelAndView
➢ 第二种:String
➢ 第三种:无返回值 void
➢ 第四种:返回自定义类型对象 根据不同的情况,使用不同的返回值。
2.3.1 返回ModelAndView
若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时 处理器方法返回 ModelAndView 比较好。
当然,若要返回 ModelAndView,则处理器方法中 需要定义 ModelAndView 对象。
在使用时,若该处理器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何 资源跳转(如对页面的 Ajax 异步响应),此时若返回 ModelAndView,则将总是有一部分多余:要么 Model 多余,要么 View 多余。
即此时返回 ModelAndView 将不合适。
2.3.2 返回String
处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址。
如果是要返回普通的字符串,而不是返回视图,我们只需要添加一个注解@ResponseBody
//处理器方法返回String -- 表示逻辑视图名称,需要配置视图解析器
@RequestMapping(value = {"/returnString-view.do"}, method = RequestMethod.POST)
// @ResponseBody 加上这个注解后,表明返回的是普通的字符串,而不是视图。
public String receiveParam(String name, Integer age, HttpServletRequest request) {
System.out.println("name = " + name + " ,age = " + age);
request.setAttribute("name", name);
request.setAttribute("age", age);
// show:逻辑视图名称,项目中配置了视图解析器
// 框架对视图执行forward转发操作。
return "show";
}
2.3.3 返回void
若处理器对请求处理后,无需跳转到其它任何资源,此时可以让处理器方法返回 void。
不能表示数据,也不能表示视图,在处理ajax的时候,可以使用void返回值。通过HttpServletResponse输出数据相应ajax请求。
ajax请求服务器端返回额的就是数据,和视图无关。
使用json依赖(pom.xml)
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
前端页面(index.jsp)
<script type="text/javascript">
$(() => {
$("#btn").click(function () {
$.ajax({
url: "test/returnVoid-ajax.do",
data: {
name: $("#userName").val(),
age: $("#userAge").val()
},
type: "post",
dataType: "json",
success: function (resp) {
alert(resp.name+"\n"+resp.age)
console.log("name = "+resp.name)
console.log("age = "+resp.age)
}
})
});
});
</script>
MyController类中的方法响应前端的ajax
@RequestMapping(value = {"/returnVoid-ajax.do"}, method = RequestMethod.POST)
public void returnVoid(String name, Integer age, HttpServletResponse response) throws IOException {
System.out.println("name = " + name + " ,age = " + age);
// 处理ajax,使用jsonstu格式
// 模拟调用service完成,返回Student对象
Student stu = new Student(name, age);
// 把结果的对象转为json格式的数据
String json = "";
if (stu != null) {
ObjectMapper om = new ObjectMapper();
json = om.writeValueAsString(stu);
System.out.println("student转化为json对象:" + json);
}
// 输出数据,响应ajax的请求
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println(json);
writer.flush();
writer.close();
}
2.3.4 返回Object
1、处理器方法也可以返回 Object 对象。这个 Object 可以是 Integer,String,自定义对象, Map,List 等。
2、但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的,与视图无关。
3、返回对象,需要使用@ResponseBody 注解,将转换后的 JSON 数据放入到响应体中。
4、可以使用对象表示的数据,响应ajax请求。
现在做ajax,主要使用json的数据格式。实现步骤:
1、加入处理json的工具库的依赖,springmvc默认使用的是jackson。
2、在springmvc配置文件之间加入<mvc:annotation-driven> 注解驱动。
等价于<==> json = om.writeValueAsString(stu);
3、在处理器方法的上面加入ResponseBody注解
等价于<==>response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println(json);
springmvc 处理器方法返回Object,可以转为json输出到浏览器,响应ajax的内部原理:
1、<mvc:annotation-driven>注解驱动。
注册驱动实现的功能是 完成Java对象到json,xml,text,二进制等数据格式的转换。
HttpMessageConveter接口:消息转换器。
功能:定义了Java对象转为json,xml等数据格式的方法。这个接口有很多的实现类。
这些实现类完成了java对象到json,java对象到xml,Java对象到二进制数据的转换。
七个实现类:
1)MappingJackson2HttpMessageConverter(使用jackson工具库中的ObjectMapper实现Java对象转为json字符串)
下面两个方法是控制器类把结果输出给浏览器时使用的
//指定转换器是否可将 clazz 类型的对
//象写到响应流中,响应流支持的媒体类型在 MediaType 中定义。
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
//将 T 类型的对象写
//到响应流中,同时指定相应的媒体类型为 contentType
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;
返回自定义对象形式
1、添加jackson依赖
2、在springmvc.xml中注册驱动
<mvc:annotation-driven/>
3、 MyController类中的方法
@RequestMapping(value = {"/returnStudentJson-ajax.do"}, method = RequestMethod.POST)
@ResponseBody
public Student returnStudentJson(String name, Integer age, HttpServletResponse response) throws IOException {
System.out.println("这是注解驱动的方式,name = " + name + " ,age = " + age);
// 处理ajax,使用jsonstu格式
// 模拟调用service完成,返回Student对象
Student stu = new Student(name, age);
return stu;
}
@ResponseBody:
1)作用:把处理器方法返回对象转化为json后,通过HttpServletResponse输出给浏览器。
2)位置:方法的定义上面。和其他注解没有顺序的关系。
4、返回对象框架的的处理流程:
1)框架会把返回Student类型,调用框架中的ArrayList<HttpMessageConvertor>中每个类的canWrite()方法,
检查哪个HttpMessageConveter接口的实现类能处理Student类型的数据--- MappingJackson2HttpMessageConveter类。
2)框架会调用实现类的write(),MappingJackson2HttpMessageConveter的write()方法,把李四同学的student对象转 为json,调用Jackson的ObjectMapper实现转为json。
3)框架会调用@ResponseBody把2的结果数据输出到浏览器,ajax请求处理完成。
返回List集合
@RequestMapping(value = {"/returnStudentListJson-ajax.do"}, method = RequestMethod.POST)
@ResponseBody
public List<Student> returnStudentListJson(String name, Integer age, HttpServletResponse response) throws IOException {
List<Student> studentList = new ArrayList<Student>();
System.out.println("这是注解驱动的方式,name = " + name + " ,age = " + age);
Student stu = new Student(name, age);
studentList.add(stu);
studentList.add(new Student("邓进",30));
studentList.add(new Student("张三",40));
// 转为json数组
return studentList;
}
注意
处理器方法返回的是String,String表示数据的,不是视图。
区分返回值String是数据,还是视图,看有没有@ResponseBody注解,如果有@ResponseBody注解,返回String就是数据,反之就是视图。
示例:
/**
* 返回字符串
* 默认使用 "Content-Type: text/plain;charset=ISO-8859-1" 导致中文有乱码
* 解决方案:给RequestMapping 增加一个属性produces,使用这个属性指定新的Context-Type.
*
* @return
*/
@RequestMapping(value = {"/returnString.do"}, method = RequestMethod.POST, produces = "text/plain;charset=utf-8")
@ResponseBody
public String returnString() {
return "fashion show!你好!";
}
2.4 解读<url-pattern/>
只有当使用<url-pattern>/<url-pattern/>的时候,才需要静态资源的配置。
2.4.1 第一种处理静态资源的方式
<mvc:default-servlet-handler/>
使用斜杠" / "
当你的项目使用了 / ,它会替代 tomcat中的default。
导致所有的静态资源都给DispatcherServlet处理,默认情况下DispatcherServlet没有处理静态资源的能力。
没有控制器对象能处理静态资源的访问。所以静态资源(html,js,图片,css)都是404错误。
动态资源some.do是可以访问的,因为我们程序中有MyController控制器对象,能处理some.do的请求。
需要在springmvc配置文件加入<mvc:default-servlet-handler/>,
原理是:加入这个标签后,框架会创建控制器对象DefaultServletHttpRequestHandler(类似我们自己创建的MyController)。
DefaultServletHttpRequestHandler这个对象可以把接收的请求转发给 tomcat的default这个servlet。
注意
<mvc:annotation-driven/>
default-servlet-handler标签 和@RequestMapping注解有冲突,需要加入annotation-driven 解决问题。
2.4.2 第二种处理静态资源的方式
<mvc:resources/>
<!-- 第二种处理静态资源的方式
mvc:resources :加入后框架会创建 ResourceHttpRequestHandler这个处理器对象。
让这个对象来处理静态资源的访问,不依赖tomcat服务器。
mapping:访问静态资源的uri地址,使用通配符**
location:静态资源在你的项目中的目录位置。
/images/**:表示images下的所有目录和所有文件。
/images/:表示静态资源的目录位置。
-->
<mvc:resources mapping="/images/**" location="/images/"/>
<mvc:resources mapping="/html/**" location="/html/"/>
Tips
我们可以把所有的静态资源都放到一个static文件目录下,这样我们的就只需要配置一个resource标签。
<mvc:resources mapping="/static/**" location="/static/"/>
2.5 解决路径问题
2.5.1 参考地址
参考地址:
在你的页面中,访问地址不加 " / "
访问的是:http://localhost:8080/spring_url_pattern/index.jsp
路径是:http://localhost:8080/spring_url_pattern/
资源index.jsp
在index.jsp发起user/some.do请求,访问地址变为http://localhost:8080/spring_url_pattern/user/some.do
当你的地址,没有以斜杠开头,例如 user/some.do,当你点击链接时,访问的地址是当前页面的地址加上链接的地址。
http://localhost:8080/spring_url_pattern/ + user/some.do
缺点:
参考地址可能会发生变化,导致出现404错误。
解决方案:
1)加入${pageContext.request.contextPath}
2)使用base标签。在你的页面中,所有不带斜杠的地址都是参考base标签,将其作为参考地址,
使用base标签的地址 + user/some.do 组成访问地址。
<base href="http://localhost:8080/spring_url_pattern/"/>
动态获取参考地址:
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/";
在页面中,访问地址加上 " / "
访问的是:http://localhost:8080/spring_url_pattern/index.jsp
路径是:http://localhost:8080/spring_url_pattern/
资源是:index.jsp
点击/user/some.do 访问地址变为http://localhost:8080/user/some.do
参考地址:服务器地址,也就是http://localhost:8080/
如果你的资源不能访问
加上${pageContext.request.contextPath}
<a href = "${pageContext.request.contextPath}/user/some.do">发起user/some.do的请求</a>
等价于<===>
<a href = "/spring_url_pattern/user/some.do">发起user/some.do的请求</a>
第三章 SSM整合开发
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对象
实现步骤:
3.1 创建数据库
使用springdb的mysql库, 表使用student(id auto_increment, name, age)
3.2 新建maven web项目
3.3 加入依赖
springmvc,spring,mybatis三个框架的依赖,jackson依赖,mysql驱动,druid连接池
jsp,servlet依赖
3.4 编写web.xml
1)注册DispatcherServlet ,目的:
1. 创建springmvc容器对象,才能创建Controller类对象。
2. 创建的是Servlet,才能接受用户的请求。
2)注册spring的监听器:ContextLoaderListener,目的: 创建spring的容器对象,才能创建service,dao等对象。
3)注册字符集过滤器,解决post请求乱码的问题。
web.xml
<!-- 注册中央调度器-->
<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:conf/dispatcherServlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- 注册监听器-->
<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>
<!-- 注册字符过滤器-->
<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.5 创建包
Controller包, service ,dao,实体类包名创建好。
3.6 配置文件
写springmvc,spring,mybatis的配置文件
1)springmvc配置文件
2)spring配置文件
3)mybatis主配置文件
4)数据库的属性配置文件
数据库的属性配置(jdbc.properties)
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.username=root
jdbc.password=020821
springmvc配置文件(dispatcherServlet)
<!-- springmvc配置文件,声明controller和其他web相关的对象 -->
<context:component-scan base-package="com.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<mvc:default-servlet-handler/>
<!--
1、响应ajax请求,返回json
2、解决静态资源访问问题
-->
<mvc:annotation-driven/>
<mvc:resources mapping="/images/**" location="/images/"/>
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.dao"/>
</bean>
<!-- 声明Service的注解@Service所在的位置-->
<context:component-scan base-package="com.service"/>
mybatis主配置文件(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>
<!-- 设置日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.domain"/>
</typeAliases>
<!-- 指定其他mapper文件的位置
找到其他文件中的sql语句
-->
<mappers>
<!--告诉 mybatis 要执行的 sql 语句的位置,可以有多个mapper文件。
使用mapper的resource属性指定mapper文件的路径。
这个路径是从target/classes路径开始的。
1、resource = “mapper文件的路径,使用 / 分割路径”。
一个mapper resource 指定一个mapper文件。
-->
<!-- <mapper resource="com/dao/StudentDao.xml"/>-->
<package name="com.dao"/>
</mappers>
</configuration>
3.7 写代码
dao接口和mapper文件, service和实现类,controller, 实体类。
3.8 写jsp页面
略。
第四章 SpringMVC核心技术
4.1 请求转发
1、处理器方法返回 ModelAndView 时,需在 setViewName()指定的视图前添加 forward:,且 此时的视图不再与视图解析器一同工作,这样可以在配置了解析器时指定不同位置的视图。
2、 视图页面必须写出相对于项目根的路径。forward 操作不需要视图解析器。 处理器方法返回 String,在视图路径前面加入 forward: 视图完整路径。
@RequestMapping(value = {"/forWard.do"}, method = RequestMethod.POST)
public ModelAndView doSome(String name, Integer age) {
System.out.println("name = " + name + ", age = " + age);
ModelAndView mv = new ModelAndView();
mv.addObject("name", name);
mv.addObject("age", age);
mv.setViewName("forward:/WEB-INF/view/show.jsp");
return mv;
}
4.2 请求重定向
在处理器方法返回的视图字符串的前面添加 redirect:,则可实现重定向跳转。
框架对重定向的操作:
框架会把Model中的简单类型的数据,转为String使用,作为hello.jsp的e请求参数使用。
目的是在于doRedirect和hello.jsp 两次请求之间的传递数据。
forWard特点:不和视图解析器一同使用,就当项目中没有视图解析器。
@RequestMapping(value = {"/doRedirect.do"}, method = RequestMethod.POST)
public ModelAndView doRedirect(String name, Integer age) {
System.out.println("name = " + name + ", age = " + age);
ModelAndView mv = new ModelAndView();
mv.addObject("name", name);
mv.addObject("age", age);
mv.setViewName("redirect:/show.jsp");
return mv;
}
param对象:获取地址栏的参数。
<p><h3>doSome传过来的参数 name = ${param.name}</h3></p>
<p><h3>doSome传过来的参数 age= ${param.age}</h3></p>
4.3 异常处理
SpringMVC 框架处理异常的常用方式:使用@ExceptionHandler 注解处理异常。
异常处理基本步骤:
1、新建Maven项目
2、加入依赖
3、新建一个自定义异常类MyUserException,再定义它的子类NameException,AgeException
4、在controller抛出NameException,AgeException
5、创建一个普通类,作用全局的异常处理类
1)在类的上面加入@ControllerAdvice
2)在类中定义方法,方法的上面加入@ExceptionHandler
6、创建处理异常的视图页面
7、创建springmvc的配置文件
1)组件扫描器,扫描@Controller注解
2)组件扫描器,扫描@ControllerAdvice所在的包名。
3)声明注解驱动
4.3.1 自定义异常类
public class AgeException extends Exception {
public AgeException() {
super();
}
public AgeException(String message) {
super(message);
}
}
public class NameException extends MyUserException{
public NameException() {
super();
}
public NameException(String message) {
super(message);
}
}
4.3.2 在controller抛出异常
@RequestMapping(value = {"/some.do"}, method = RequestMethod.POST)
public ModelAndView doSome(String name, Integer age) throws AgeException, NameException {
System.out.println("name = " + name + ", age = " + age);
if (age == null || age > 120) {
throw new AgeException("年龄太大!!");
}
if (!"邓进".equals(name)) {
throw new NameException("姓名不正确!!");
}
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "欢迎使用springmvc做web开发");
mv.addObject("fun", "执行的是doSome方法");
mv.addObject("name", name);
mv.addObject("age", age);
mv.setViewName("forward:/WEB-INF/view/show.jsp");
return mv;
}
4.3.3 创建异常处理类
/**
* @author kangkang
* @ControllerAdvice : 控制器增强(也就是说给控制器增加功能,--异常处理功能)
* 位置:在类的上面
* 特点:必须让框架知道这个注解所在的包名,需要在springmvc配置文件声明组件扫描器
* 指定@ControllerAdvice所在的包名
*/
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理异常的方法和控制器方法的定义一样,可以有多个参数,可以有ModelAndView,String ,void 对象类型的返回值.
* 形参:Exception,表示Controller中抛出的异常对象.
* 通过形参可以获取发生的异常信息.
*/
@ExceptionHandler(value = NameException.class)
public ModelAndView doNameException(Exception exception) {
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "当前用户只能是用户[ 邓进 ]能够登录");
mv.addObject("ex", exception);
mv.setViewName("nameError");
return mv;
}
/**
* @param exception
* @return
*/
@ExceptionHandler(value = AgeException.class)
public ModelAndView doAgeException(Exception exception) {
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "你的年龄不能大于120或为空!!");
mv.addObject("ex", exception);
mv.setViewName("ageError");
return mv;
}
/**
* 处理其他异常信息
* 除开NameException和AgeException之外的异常信息
*/
@ExceptionHandler
public ModelAndView doOtherException(Exception exception) {
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "这是其他的异常!");
mv.addObject("ex", exception);
mv.setViewName("defaultError");
return mv;
}
}
4.3.4 创建springmvc配置文件
<!-- 关键声明 -->
<!-- 1)组件扫描器,扫描@Controller注解 -->
<context:component-scan base-package="controller"/>
<!-- 2)组件扫描器,扫描@ControllerAdvice所在的包名 -->
<context:component-scan base-package="handler"/>
<!-- 3)声明注解驱动 -->
<mvc:annotation-driven/>
4.4 拦截器
SpringMVC 中的 Interceptor 拦截器是非常重要和相当有用的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。
拦截器是全局的,可以对多个Controller做拦截。
一个项目中可以有0个或多个拦截器。他们在一起拦截用户的请求。
拦截器常用在:用户登录处理,权限检查,记录日志。
4.4.1 实现步骤
1)新建maven项目
2)加入依赖
3)创建controller类
4)创建一个普通类,作为拦截器使用
1.实现HandlerInterceptor接口
2.实现接口中的三个方法
5)创建springmvc的配置文件
1.组件扫描器,扫描@Controller注解
2.声明拦截器,并指定拦截器的请求uri地址。
4.4.2 实现接口
public class MyInterceptor implements HandlerInterceptor {}
4.4.3 三个方法
preHandler()
/**
* 返回值boolean
重要:
是整个项目的入口,门户。当preHandler返回true 请求可以被处理
当preHandler返回false,请求到此方法就截止。
* <p>
* 特点:
* 1、方法在控制器方法之前先执行的,用户的请求首先到达此方法。
* <p>
* 2、在这个方法中可以获取请求的信息,验证请求是否符合要求,可以验证用户是否登录,验证用户是否有权限访问某个链接地址(url)
* 如果验证失败,可以截断请求,请求不能被处理
* 如果验证成功,可以放行请求,此时控制器方法才能执行。
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器的MyInterceptor的preHandler()方法");
return true;
}
postHandler()
/**
* 特点:
* 1、在处理器方法之后执行的
* 2、能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的数据和视图,可以影响到最后的执行结果。
* 3、主要是对原来的执行结果做二次修正。
*
* @param request
* @param response
* @param handler 被拦截的处理器对象MyController
* @param modelAndView 处理器方法的返回值
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器的MyInterceptor的postHandler()方法");
}
afterCompletion()
/**
* 最后执行的方法
* 特点:
* 1、在请求处理完成后执行的。框架中规定是当你的视图处理完成后,对视图执行了forward,就认为请求处理完成。
* 2、一般做资源回收工作的,程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收。
* @param request
* @param response
* @param handler 被拦截器拦截的处理器对象
* @param ex 程序中发生的异常
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("拦截器的MyInterceptor的afterCompletion()方法");
}
4.4.4 声明拦截器
<!-- 声明拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--指定拦截的请求uri地址
path:就是uri地址,可以使用通配符 **
** : 表示任意的字符,文件或者多级目录和目录中的文件。
-->
<mvc:mapping path="/**"/>
<!-- 声明拦截器对象-->
<bean class="handler.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
4.4.5 多个拦截器
springmvc配置文件
<!-- 声明拦截器-->
<mvc:interceptors>
<!-- 声明第一个拦截器-->
<mvc:interceptor>
<!--指定拦截的请求uri地址
path:就是uri地址,可以使用通配符 **
** : 表示任意的字符,文件或者多级目录和目录中的文件。
-->
<mvc:mapping path="/**"/>
<!-- 声明拦截器对象-->
<bean class="handler.MyInterceptor01"/>
</mvc:interceptor>
<!-- 声明第二个拦截器-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="handler.MyInterceptor02"></bean>
</mvc:interceptor>
</mvc:interceptors>
多个拦截器执行顺序
按照配置文件中的拦截器配置先后顺序,可以联想递归的思想进行理解。
111111-拦截器的MyInterceptor的preHandler()方法
222222-拦截器的MyInterceptor的preHandler()方法
执行MyController执行的doSome方法
222222-拦截器的MyInterceptor的postHandler()方法
111111-拦截器的MyInterceptor的postHandler()方法
222222-拦截器的MyInterceptor的afterCompletion()
111111-拦截器的MyInterceptor的afterCompletion()方法
注意:
1、只有当多个拦截器中的preHandler都返回true时才能成功访问MyController方法。
4.5 拦截器与过滤器的区别
1、过滤器是servlet中的对象,拦截器是框架中的对象。
2、过滤器是实现Filter接口的对象,拦截器是实现HandlerInterceptor。
3、过滤器是用来设置request、response的参数,属性的,侧重对数据过滤的。
拦截器是用来验证请求的,能截断请求。
4、过滤器是在拦截器之前先执行的。
5、过滤器是Tomcat服务器创建的对象,拦截器是springmvc中创建的对象。
6、过滤器是一个执行时间点。
拦截器有三个执行时间点。
7、过滤器可以处理jsp,js,html等等。
拦截器是侧重拦截对Controller的对象。
如果你的请求不能被DispathcerServlet(中央调度器)接收,这个请求不会执行拦截器内容。
8、拦截器拦截普通类方法的执行,过滤器过滤servlet请求
4.6 springmvc执行流程
4.6.1 执行流程分析
(1)浏览器提交请求到中央调度器
(2)中央调度器直接将请求转给处理器映射器。
(3)处理器映射器会根据请求,找到处理该请求的处理器,并将其封装为处理器执行链后
返回给中央调度器。
(4)中央调度器根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器。
(5)处理器适配器调用执行处理器。
(6)处理器将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给
处理器适配器。
(7)处理器适配器直接将结果返回给中央调度器。
(8)中央调度器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象。
(9)视图解析器将封装了的视图对象返回给中央调度器
(10)中央调度器调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。
(11)中央调度器响应浏览器。
处理器映射器的作用:
根据请求,从springmvc容器对象中获取处理器对象(MyConytroller controller = ctx.getBean("some.do"))框架把找到的 处理器对象放到一个叫做处理器执行链(HandlerExecutionChain)的类中保存。
HandlerExecutionChain:
类中保存着,1、处理器对象(MyController);
2、项目中所有的拦截器List<HandlerInterceptor> interceptorList
DispatcherServlet把上面的HandlerExecutionChain中处理器对象交给了处理器适配器对象(多个)
处理器适配器:
springmvc框架中的对象,需要实现HandlerAdapter接口。
处理器适配器作用:执行处理器方法(调用MyController.doSome()得到返回值ModleAndView)
DispatcherServlet把3中获取的ModelAndView交给了视图解析器对象。
视图解析器:
springmvc中的对象,需要实现ViewResoler接口(可以有多个)
视图解析器作用:
组成视图完整路径,使用前缀,后缀。并创建View对象。
View是一个接口,表示视图的,在框架中jsp,html不是string表示,而是使用View和它的实现类表示视图。
InternalResourceView:视图类,表示jsp文件,视图解析器ViewResoler会创建InternalResourceView类对象。
这个对象的里面,有一个属性url = /WEB_INF/view/sho
DispatcherServlet把刚刚创建的View对象获取到,调用View类自己的方法,把Model数据放入到request作用域。执行对象视图的forward。请求结束。
648823073952)]
4.6.1 执行流程分析
(1)浏览器提交请求到中央调度器
(2)中央调度器直接将请求转给处理器映射器。
(3)处理器映射器会根据请求,找到处理该请求的处理器,并将其封装为处理器执行链后
返回给中央调度器。
(4)中央调度器根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器。
(5)处理器适配器调用执行处理器。
(6)处理器将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给
处理器适配器。
(7)处理器适配器直接将结果返回给中央调度器。
(8)中央调度器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象。
(9)视图解析器将封装了的视图对象返回给中央调度器
(10)中央调度器调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。
(11)中央调度器响应浏览器。
处理器映射器的作用:
根据请求,从springmvc容器对象中获取处理器对象(MyConytroller controller = ctx.getBean("some.do"))框架把找到的 处理器对象放到一个叫做处理器执行链(HandlerExecutionChain)的类中保存。
HandlerExecutionChain:
类中保存着,1、处理器对象(MyController);
2、项目中所有的拦截器List<HandlerInterceptor> interceptorList
DispatcherServlet把上面的HandlerExecutionChain中处理器对象交给了处理器适配器对象(多个)
处理器适配器:
springmvc框架中的对象,需要实现HandlerAdapter接口。
处理器适配器作用:执行处理器方法(调用MyController.doSome()得到返回值ModleAndView)
DispatcherServlet把3中获取的ModelAndView交给了视图解析器对象。
视图解析器:
springmvc中的对象,需要实现ViewResoler接口(可以有多个)
视图解析器作用:
组成视图完整路径,使用前缀,后缀。并创建View对象。
View是一个接口,表示视图的,在框架中jsp,html不是string表示,而是使用View和它的实现类表示视图。
InternalResourceView:视图类,表示jsp文件,视图解析器ViewResoler会创建InternalResourceView类对象。
这个对象的里面,有一个属性url = /WEB_INF/view/sho
DispatcherServlet把刚刚创建的View对象获取到,调用View类自己的方法,把Model数据放入到request作用域。执行对象视图的forward。请求结束。