三层架构和MVC设计模型
入门
入门环境搭建步骤
1.创建maven工程,选择webapp项目
2.补全目录结构
在main目录下创建java和resources目录分别标记为 源码根和resources 根
3.导入pom文件
4.在web.xml中添加前端控制器:org.springframework.web.servlet.DispatcherServlet 为Servlet
5.配置tomcat服务器
1.创建maven工程,选择webapp项目
2.补全目录结构
在main目录下创建java和resources目录分别标记为 源码根和resources 根
3.在resources目录中创建xml配置文件
4.在web.xml中添加前端控制器:org.springframework.web.servlet.DispatcherServlet 为Servlet
5.配置tomcat服务器
入门代码编写
1.删除index.jsp文件重新创建带头部的
2.在新的index.jsp中定义超链接进行跳转
3.编写HelloController控制器类
4.在springmvc.xml中引入新的约束、开启注解扫描
5.为HelloController控制器类添加@Controller和@RequestMapping(path = "/hello")注解
6.在web.xml的前端控制器中写初始化参数标签来加载XML配置文件来完成IOC容器的创建
7.在springmvc.xml中配置视图解析器bean对象,并开启springMVC框架注解的支持
8.定义返回jsp页面success.jsp
1.删除index.jsp文件重新创建带头部的
2.在新的index.jsp中定义超链接进行跳转
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门程序</h3>
<a href="/hello">入门程序</a>
</body>
</html>
3.编写HelloController控制器类
package com.tiger.controller;
//控制器类
public class HelloController {
public String sayHello(){
System.out.println("Hello SpringMVC");
return "success";//默认代表返回的jsp文件的名字
}
}
4.在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">
<!--开启注解扫描-->
<context:component-scan base-package="com.tiger"></context:component-scan>
</beans>
5.为HelloController控制器类添加@Controller和@RequestMapping(path = “/hello”)注解
package com.tiger.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
//控制器类
@Controller
public class HelloController {
@RequestMapping(path = "/hello")
public String sayHello(){
System.out.println("Hello SpringMVC");
return "success";//默认代表返回的jsp文件的名字
}
}
6.在web.xml的前端控制器中写初始化参数标签来加载XML配置文件来完成IOC容器的创建
7.在springmvc.xml中配置视图解析器bean对象,并开启springMVC框架注解的支持
<!--视图解析器对象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置文件前缀目录-->
<property name="prefix" value="/WEB-INF/pages/"></property>
<!--配置文件后缀名-->
<property name="suffix" value=".jsp"></property>
</bean>
<!--开启springMVC框架注解的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
8.定义返回jsp页面success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门成功</h3>
</body>
</html>
入门案例流程总结
1.启动服务器,加载一些配置文件
* DispatcherServlet对象被创建
* springmvc.xml被加载了
* HelloController创建成对象
* InternalResourceViewResolver视图解析器对象被创建
* 因为在springmvc.xml中开启了springMVC框架注解的支持@RequestMapping(path = "/hello")注解也生效了
2.发送请求,后台处理请求:
入门案例组件介绍
1.客户端发送请求到达前端控制器
2.前端控制器找处理器映射器
3.处理器映射器根据请求的路径来找到Controller中对应的方法并返回给前端控制器
4.前端控制器拿着方法找处理器适配器来执行
5.请求路径访问的任何Controller的任何方法都能适配上,最终转为适配器去找处理器执行最终的方法
6.处理器也叫Controller来执行方法,并返return中的值 即success
7.处理器适配器将success返回给前端控制器
8.前端控制器拿着success去找视图解析器来解析
9.视图解析器返回解析结果给前端控制器
10.前端控制器拿着解析结果来跳转到相应的jsp页面
< mvc:annotation-driven>的作用
1.开启springMVC框架注解的支持
2.在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为springMVC的三大组件。
使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping(处理器映射器)和RequestMappingHandlerAdapter(处理器适配器),
可用在springmvc.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置
@RequestMapping注解的作用
作用:
用于建立请求URL和处理请求方法之间的对应关系。
位置:
可以是类上,也可以是方法上。
属性:
value:用于指定请求的URL。它和path属性的作用是一样的。
method:用于指定请求的方式。
params:限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样。
headers:限制请求消息必须包含对应的请求头才能请求成功。
/**
* RequestMapping注解
* params ="username":要求请求参数的key为username,value不限制
* params ="username=heihei":要求请求参数的key为username,value为heihei
* @return
*/
@RequestMapping(path = "/testRequestMApping",method = RequestMethod.GET,params ="username=heihei",headers ="Accept")
public String testRequestMApping(){
System.out.println("测试RequestMapping注解....");
return "success";
}
请求参数绑定入门
请求参数默认封装到@RequestMapping("/testParam")
注解的类对应的方法的参数列表中
请求参数绑定实体类型
如果实体类中包含引用类型,则用点号来指定封装目标
配置解决中文乱码的过滤器
利用过滤器解决中文乱码
<!--配置解决中文乱码的过滤器-->
<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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
请求参数绑定集合类型
自定义类型转换器转换异常
表单提交的请求参数都是String类型,但是后台可以成功封装为Integer等等。
是因为spring自动将 String–>Integer、Double…
甚至日期都可以转换。“2017-06-06”—> 2017-06-06
但是日期格式是固定的,如果日期字符串为"2017/06/06"就可能会转换失败
自定义类型转换器代码编写
1.定义一个类,实现Converter接口,该接口有两个泛型
2.在convert方法中写转换逻辑
3.在springmvc.xml中配置类型转换器组件
4.开启对类型转换器组件的支持
1.定义一个类,实现Converter接口,该接口有两个泛型
2.在convert方法中写转换逻辑
package com.tiger.utils;
import org.springframework.core.convert.converter.Converter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 把字符串转换成日期
*/
public class StringToDateConverter implements Converter<String, Date> {
/**
*String source 传入进来的字符串
* @param source
* @return
*/
@Override
public Date convert(String source) {
if(source==null){
throw new RuntimeException("请传入数据");
}
DateFormat df=new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
//把字符串转换成日期
return df.parse(source);
} catch (Exception e) {
throw new RuntimeException("数据类型转换出现错误");
}
}
}
3.在springmvc.xml中配置类型转换器组件
<!--配置自定义类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.tiger.utils.StringToDateConverter"></bean>
</set>
</property>
</bean>
4.开启对类型转换器组件的支持
在Controller中获取原生ServletAPI(Request等等)
@RequestParam注解
用于将请求参数和方法参数进行绑定
@RequestBody注解
作用:
用于获取请求体内容。直接使用得到是 key=value$key=value...结构的数据。
get请求不适用
属性:
requidred:是否必须有请求体。默认值为:true。当取值为true时,get请求方式会报错。如果取值为false,get请求得到为null。
使用时机:
会在异步中使用
@PathVariable注解
1.作用:拥有绑定URL中的占位符的,例如:URL中有/delete/{id},id就是占位符
2.属性
1.value:指定URL中的占位符名称
3.Restful风格的URL
1.请求路径一样,可以根据不同的请求方式去执行后台的不同方法
2.restful风格的URL优点
1.结构清晰
2.符合标准
3.易于理解
4.扩展方便
Restful编程风格
请求路径相同,根据请求方式和占位符来区分具体请求的是哪个方法
@RequestHeader注解
作用:
用于获取请求消息头
属性:
value:提供消息头名称
required:是否必须有此消息头
注:
在实际开发中此注解使用很少
@CookieValue注解
@ModelAttribute注解
作用:
出现在方法上,表示当前方法会在请求控制器的方法执行之前,先执行。
出现在参数上,获取指定的数据给参数赋值
属性:
value:用于获取数据的key。key可以是POJO的属性名称,也可以是map结构的key。
应用场景:
当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据
例如:
我们在编辑一个用户时,用户有一个创建信息字段,该字段的值不允许被修改的。
在提交表单数据是肯定没有此字段的内容,一旦更新会把该字段内容置为null,此时就可以使用此注解解决问题。
@SessionAttributes注解
作用:
用于多次执行控制器方法间的参数共享
属性:
value:用于指定存入的属性名称
type:用于指定存入的数据类型
响应数据和结果视图
请求方法的返回值分类:
字符串 :
Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器解析物理视图的地址
void:
没有返回值则默认请求,请求路径.jsp。利用Servlet原生API,有三种办法进行响应
ModelAndView:此对象是Spring提供的一个对象,可以用来调整具体的JSP视图,
它可以通过视图解析器跳转到具体页面
返回字符串的底层也是这种方式
关键字实现跳转:
不会被视图解析器解析
响应返回值是String类型
返回值是void类型
返回ModelAndView类型
关键字实现跳转
过滤静态资源
当引入JQuery时该请求也会被前端控制器拦截,前端控制器拦截除了jsp资源以外的请求。
JQuery、CSS、HTML…等静态资源都会被拦截,分发给Controller取匹配方法。造成请求404。需要在springmvc.xml中配置过滤静态资源
<!--配置前端控制器,哪些静态资源不拦截-->
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
异步请求与响应json
异步请求时,在请求方法参数上加@RequestBody来获取请求体,并封装进参数,在返回值类型前加@ResponseBody来指定此类型为响应体以json格式响应回去,供前台的回调函数使用。
springMVC异常处理
1.编写自定义异常类(做提示信息的)
package com.tiger.exception;
/**
* 自定义异常类
*/
public class SysException extends Exception{
//存储提示信息
private String message;
public SysException(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
2.编写异常处理器
package com.tiger.exception;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 异常处理器
*/
public class SysExceptionResolver implements HandlerExceptionResolver {
/**
* 处理异常业务逻辑
* @param httpServletRequest
* @param httpServletResponse
* @param handler
* @param ex
* @return
*/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception ex) {
//获取到异常对象
SysException e=null;
if(ex instanceof SysException){
e= (SysException) ex;
}else{
e=new SysException("系统在维护");
}
//创建ModelAndView对象
ModelAndView mv=new ModelAndView();
mv.addObject("errorMsg",e.getMessage());
mv.setViewName("error");
return mv;
}
}
3.配置异常处理器(跳转到提示页面)
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>error.jsp</title>
</head>
<body>
${errorMsg}
</body>
</html>
4.在springmvc.xml配置异常处理器
<!--配置异常处理器-->
<bean id="sysExceptionResolver" class="com.tiger.exception.SysExceptionResolver"></bean>
执行过程
springMVC拦截器
拦截器和过滤器很相似。在执行Controller之前执行。
拦截器和过滤器的区别:
过滤器:
是servlet规范中的一部分,任何java web工程都可以使用
在url-pattern中配置了/*之后可以对所有要访问的资源拦截
拦截器:
是springmvc框架自己的,只有使用了springMVC框架的工程才能使用
他只会拦截访问Controller的方法,如果访问的是jsp,html,css,image或者js是不会进行拦截的
想要自定义拦截器,必须实现:HandlerInterceptor接口。
环境搭建
1.新建webapp模块
2.导入mvn依赖
3.补全目录结构
4.在web.xml中配置前端控制器和解决中文乱码的过滤器
5.在resources中新建springmvc.xml配置文件
6.在springmvc.xml配置文件中开启注解扫描、配置视图解析器、配置不拦截静态资源、开启mvc注解支持
拦截器编写
1.编写拦截器类,实现HandlerInterceptor接口
package com.tiger.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义拦截器
*/
public class MyInterceptor1 implements HandlerInterceptor {
/**
* 预处理,controller方法执行前
* @param request
* @param response
* @param handler
* @return true:放行,执行下一个拦截器,如果没有则执行controller中的方法
* false:不放行 可以利用request和response跳转到别的页面
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("MyInterceptor1执行了。。。");
return true;
}
}
2.配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器-->
<mvc:interceptor>
<!--要拦截具体的方法-->
<mvc:mapping path="/user/*"/>
<!--不要拦截的方法-->
<!--<mvc:exclude-mapping path=""/>-->
<!--配置拦截器对象-->
<bean class="com.tiger.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>
</mvc:interceptors>
分析:
拦截器接口中的方法
定义多个拦截器
package com.tiger.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 MyInterceptor1 implements HandlerInterceptor {
/**
* 预处理,controller方法执行前
* @param request
* @param response
* @param handler
* @return true:放行,执行下一个拦截器,如果没有则执行controller中的方法
* false:不放行 可以利用request和response跳转到别的页面
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("MyInterceptor1执行了。。。前111");
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
/**
* 后处理方法 controller执行后 success.jsp执行之前 此方法执行
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了。。。后111");
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
}
/**
* success.jsp页面执行后,该方法会执行
* @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("MyInterceptor1执行了。。。最后111");
}
}
package com.tiger.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方法执行前
* @param request
* @param response
* @param handler
* @return true:放行,执行下一个拦截器,如果没有则执行controller中的方法
* false:不放行 可以利用request和response跳转到别的页面
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("MyInterceptor1执行了。。。前222");
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
/**
* 后处理方法 controller执行后 success.jsp执行之前 此方法执行
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了。。。后222");
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
}
/**
* success.jsp页面执行后,该方法会执行
* @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("MyInterceptor1执行了。。。最后222");
}
}
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器1-->
<mvc:interceptor>
<!--要拦截具体的方法-->
<mvc:mapping path="/user/*"/>
<!--不要拦截的方法-->
<!--<mvc:exclude-mapping path=""/>-->
<!--配置拦截器对象-->
<bean class="com.tiger.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>
<!--配置拦截器2-->
<mvc:interceptor>
<!--要拦截具体的方法-->
<mvc:mapping path="/**"/>
<!--不要拦截的方法-->
<!--<mvc:exclude-mapping path=""/>-->
<!--配置拦截器对象-->
<bean class="com.tiger.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
执行顺序