SpringMVC
SpringMVC的基本概念
什么是MVC
是一种基于两种形式,一种是C/S架构,也就是客户端/服务器,
另一种是B/S架构,也就是浏览器/服务器. 在JavaEE中,几乎全是基于B/S架构的开发,
那么在B/S架构中,系统标准的三层架构包括:表现层,业务层,持久层.
什么是SpringMVC?
SpringMVC是一种基于java实现的MVC设计模型的请求驱动类型的轻量级WEB框架,为目前最主流的MVC框架之一,他通过一套注解,让一个简单的java类成为处理请求的控制器,无需实现任何接口.同时还支持RESTful编程风格的请求
MVC设计模型:
M: model 模型 javaBean对象 一般用于封装数据
V: view 视图 JSP/Html 一般用于展示数据
C: Controller 控制器 Servlet 一般用于处理程序逻辑
SpringMvc和Struts2:
共同点:
他们都是表现层的框架,都是基于MVC模型编写的
他们的底层都离不开ServletAPI
他们的处理请求的机制都是一个核心控制器
区别:
SpringMVC的入口是Servlet , Struts2的入口是Filter
SpringMVC是基于方法设计的, Struts2是基于类设计的,Struts2每次执行都会创建一个动作类,而SpringMVC只会创建一个类,执行时调用类中的方法.
SpringMVC更加简洁,同时还支持JSR303,处理ajax的请求更方便
Struts2的OGNL表达式使页面的开发效率相比SpringMVC更高,但执行效率并没有比JSTL提升,尤其是struts2的表单标签,远没有html执行效率高.
SpringMVC搭建环境
在New Module的 Properties属性添加插件(解决maven项目创建过慢):
Name:archetypeCatalog Value:internal
创建java目录: java,resource目录
pom.xml文件
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<!--Spring MVC依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
web.xml文件配置:
<!-- 前端控制器的配置-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
//springmvc提供的类
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--加载springmvc.xml配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--一般servlet只有当发送请求时才创建
配置该参数,只要服务器一启动,就会创建servlet对象,
servlet对象一创建,就会去加载springmvc.xml文件
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern> / :不管发什么请求,都会经过servlet
</servlet-mapping>
<!--配置解决中文乱码的过滤器-->
<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>
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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解的扫描-->
<context:component-scan base-package="com.tulun"></context:component-scan>
<!--配置视图解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--prefix: 文件所在的目录-->
<property name="prefix" value="/WEB_INF/pages/"/>
<!--文件的后缀名-->
<property name="suffix" value=".jsp"/>
</bean>
<!--开启SpringMVC框架的注解的支持-->
<mvc:annotation-driven/>
</beans>
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>
HelloController.java文件:
//控制器的类 ,用来接收请求
@Controller
public class HelloController {
//在方法上面添加请求的映射
//(path="/hello" 那么以后/hello就是该方法的请求路径)
@RequestMapping(path = "/hello")
public String sayHello() {
System.out.println("Hello SpringMVC");
//默认返回的值为当前jsp文件的名字
return "success";
}
}
WEB-INF目录下添加pages/success.jsp文件:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门成功</h3>
</body>
</html>
SpringMVC运行的步骤
1.导入依赖
2.在web.xml配置前端控制器(在起启动服务器的时候就加载springmvc.xml文件)
3.在index.jsp文件创建一个链接
入门程序
4.在springmvc.xml文件
<!--开启注解的扫描-->
<context:component-scan base-package="com.tulun"></context:component-scan>
当你点开该链接,就会去该包下的类查找index.jsp文件的 的值(也就是类中的方法)
5.找到之后
@RequestMapping(path="/hello")
public String sayHello() {
System.out.println("Hello SpringMVC");
//默认返回的值为当前jsp文件的名字
return "success";
}
6.接下来在springmvc.xml文件配置视图解析器
<!--配置视图解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--prefix: 文件所在的目录-->
<property name="prefix" value="/WEB-INF/pages/"/>
<!--文件的后缀名-->
<property name="suffix" value=".jsp"/>
</bean>```
以上两个配置的意义:就会去在/WEB-INF/pages/目录下找名字为success.jsp的文件
所以需要在该目录下创建该文件success.jsp(例:此处为成功请求页面)
常用注解
@RequestMapping注解
用于建立请求URL和处理请求方法之间的对应关系
可以放在方法上,也可以是类
试例:
<a href="controller/testRequestMapping">RequestMapping注解</a>
@RequestMapping(path = "/controller")
public class HelloController {
@RequestMapping(path = "/testRequestMapping")
public String testRequestMapping() {
}
}
属性:
value和path的作用是一样的
@RequestMapping(path = "/controller")
public class HelloController {
@RequestMapping(value = "/testRequestMapping")
public String testRequestMapping() {
}
}
method: 请求方式
//method={RequestMethod.POST} 表示该方法的请求必须为 post 方式 (为枚举类型)
@RequestMapping(path = "/testRequestMapping",method={RequestMethod.POST})
public String testRequestMapping() {
}
params: 请求的时候必须传入一个 username的参数 如果params = {“username=hehe”}传入的参数必须为这样 ?username=hehe
@RequestMapping(path = "/testRequestMapping",params ={"username"})
public String testRequestMapping() {
}
<a href="controller/testRequestMapping?username=haha">RequestMapping注解</a>
@RequestParam:
把请求中指定名称的参数给控制器中的形参赋值
<a href="anno/testRequestParam?name=haha">RequestParam</a>
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam(value = "name") String username) {
System.out.println("执行了...");
return "success";
}
@RequestBody:
获取到请求体的内容
<form action="/anno/testRequestBody" method="post">
姓名: <input type="text" name="username"/><br/>
密码: <input type="text" name="age"/><br/>
<input type="submit" value="提交"/>
</form>
/**
* 获取到请求体的内容
* @param body
* @return
*/
@RequestMapping("testRequestBody")
public String testRequestBody(@RequestBody String body) {
System.out.println("执行了...");
return "success";
}
@PathVaribale:
和restful风格很像 path="/user/{id}" 传一个占位符
RESTful风格URL:
优点:节后清晰,符合标准,易于理解,扩展方便,更利于缓存
原来方式:
UserController类
path="/user/save"
save
path="/user/update"
update
path="/user/findAll"
findAll
restful方式: 根据不同的请求方式,找到方法执行
UserController类
path="/user" post
save
path="/user" put
update
path="/user" get
findAll
path="/user/{id}" get
findById(id)
localhost:8080/user/10 get(请求方式) 查询的是findById
localhost:8080/user get 查询的是findAll
@SessionAttribute
anno.jsp文件
<%--SessionAttritubes--%>
<a href="anno/testSessionAttributes">SessionAttributes</a>
<a href="anno/getSessionAttribute">SessionAttributes</a>
<a href="anno/delSessionAttribute">SessionAttributes</a>
AnnoController.java
@SessionAttributes("msg") //将数值存入Session域
public class AnnoController {
/**
* testSessionAttributes注解 向session存值
* @return
*/
@RequestMapping("/testSessionAttribute")
public String testSessionAttributes(Model model) {
System.out.println("testSessionAttributes...");
//将一组键值对存入model对象 会存储到Request域对象中
model.addAttribute("msg","meimei");
return "success";
}
/**
* 获取值
* @param modelMap
* @return
*/
@RequestMapping("/getSessionAttribute")
public String testGetSessionAttributes(ModelMap modelMap) {
System.out.println("testSessionAttributes...");
String msg = (String)modelMap.get("msg");
System.out.println(msg);
return "success";
}
/**
* 删除值
* @param sessionStatus
* @return
*/
@RequestMapping("/delSessionAttribute")
public String testDelSessionAttributes(SessionStatus sessionStatus) {
System.out.println("testSessionAttributes...");
//清空Session域
sessionStatus.setComplete();
return "success";
}
}
success.jsp
<!--说明不忽略EL表达式-->
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
${ requestScope }
${ sessionScope }
返回值
response.jsp文件
<a href="user/testString">TestString</a>
<a href="user/testVoid">TestVoid</a>
UserController.java文件
//返回值为字符串
@RequestMapping(path = "/testString")
public String testString(Model model) {
System.out.println("testString...");
//模拟从数据库中查询User对象
User user = new User();
user.setUname("fly");
user.setAge(19);
user.setDate(new Date());
//model存对象
model.addAttribute("user",user); //存入request域
return "success";
}
//返回值为void 注:如果没有返回值,会默认去WEB-INF/pages/user/找testVoid.jsp文件
@RequestMapping(path = "/testVoid")
public void testVoid(HttpServletRequest request,HttpServletResponse response) throws Exception {
System.out.println("testVoid...");
//请求转发 手动转发不会调用视图解析器 所以要自己写路径
request.getRequestDispatcher("WEB-INF/pages/success.jsp").forward(request,response);
//重定向 会重定向请求index.jsp
response.sendRedirect(request.getContextPath()+"/index.jsp");
//设置中文乱码
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//会直接进行响应
response.getWriter().println("你好");
}
异常处理
异常处理思路:Controller调用service ,service调用dao,异常都是向上抛出的,最终由DispatcherServlet异常处理器进行异常的处理.
SpringMVC异常处理:在前端控制器配置一个 异常处理器(组件).
1.编写自定义异常类(做提示信息的)
public class SysException extends Exception{
//存储提示信息
private String message;
public SysException(String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
2.编写异常处理器
public class SysExceptionResolver implements HandlerExceptionResolver {
/**
* 处理异常的业务逻辑
* @param request
* @param response
* @param o
* @param e
* @return
*/
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) {
//获取异常对象
SysException exception = null;
if(e instanceof SysException) {
exception = (SysException)e;
} else {
exception = new SysException("系统正在维护...");
}
//创建ModelAndView
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg",exception.getMessage());
//表示往哪去跳转
mv.setViewName("error");
return mv;
}
}
3.配置异常处理器(跳转到提示页面)
<!--配置异常处理器-->
<bean id="sysExceptionResolver" class="com.tulun.exception.SysExceptionResolver"></bean>
SpringMVC拦截器
拦截器是springMVC框架自己的,只有使用了SpringMVC框架后才能用
过滤器是servlet规范中的一部分,任何web项目都可以使用
拦截器只会拦截访问的控制器(Controller)的方法,如果访问的是jsp,html,css,image都不会拦截
过滤器是url-pattern中配置了 /* 之后,对所有访问资源进行拦截
1.编写拦截器类 实现HandlerInterceptor接口
public class MyInterceptor implements HandlerInterceptor {
/**
* 预处理 在controller方法执行前执行
* @param request
* @param response
* @param handler
* @return true:放行,执行下一个拦截器,如果没有,执行controller方法
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器执行了....前");
//页面跳转
// 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("拦截器执行了....后");
}
/**
* 在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("拦截器执行了....最后");
}
}
2.配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器-->
<mvc:interceptor>
<!--要拦截的具体的方法-->
<mvc:mapping path="/user/*"/>
<!--不要拦截的方法
<mvc:exclude-mapping path=""/>-->
<!--配置拦截器对象-->
<bean id="myInterceptor" class="com.tulun.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>