springmvc笔记
1、springmvc基础知识
1.1、什么是springmvc(what)
Spring为展现层提供的基于MVC设计理念的web框架,是目前最主流的MVC框架之一
1.2、为什么要使用springmvc(why)
它是一个典型的教科书式的mvc构架,而不像struts等都是变种或者不是完全基于mvc系统的框架,对于初学者或者想了解mvc的人来说我觉得 spring是最好的,它的实现就是教科书!
spring框架已经是java web开发很主流的框架,这个框架有很多优点当然也有它的不足之处,比于之前的servlet,它一定程度上简化了开发人员的工作,使用servlet的话需要每个请求都去在web.xml中配置一个servlet节点,而Spring 中的DispatcherServlet他会拦截所有的请求,进一步去查找有没有合适的处理器,一个前端控制器就可以。
1.3、怎样使用springmvc(how)
看第二章,代码书写部分
1.4、springmvc知识点
- springmvc的工作流程
过程说明:
1、 用户向服务端发送一次请求,这个请求会先到前端控制器DispatcherServlet(也叫中央控制器)。
2、DispatcherServlet接收到请求后会调用HandlerMapping处理器映射器。由此得知,该请求该由哪个Controller来处理(并未调用Controller,只是得知)
3、DispatcherServlet调用HandlerAdapter处理器适配器,告诉处理器适配器应该要去执行哪个Controller
4、HandlerAdapter处理器适配器去执行Controller并得到ModelAndView(数据和视图),并层层返回给DispatcherServlet
5、DispatcherServlet将ModelAndView交给ViewReslover视图解析器解析,然后返回真正的视图。
6、DispatcherServlet将模型数据填充到视图中
7、DispatcherServlet将结果响应给用户
组件说明:
DispatcherServlet:前端控制器,也称为中央控制器,它是整个请求响应的控制中心,组件的调用由它统一调度。
HandlerMapping:处理器映射器,它根据用户访问的 URL 映射到对应的后端处理器 Handler。也就是说它知道处理用户请求的后端处理器,但是它并不执行后端处理器,而是将处理器告诉给中央处理器。
HandlerAdapter:处理器适配器,它调用后端处理器中的方法,返回逻辑视图 ModelAndView 对象。
ViewResolver:视图解析器,将 ModelAndView 逻辑视图解析为具体的视图(如 JSP)。
Handler:后端处理器,对用户具体请求进行处理,也就是我们编写的 Controller 类。
- @RequestMapping注解
- @RequestMapping注解使用在类上表示为此类中所有方法的请求路径添加了一个基准
@RequestMapping("/haha")
@Controller
public class MyFirstController {
@RequestMapping("/hello")
public String myfirstRequest(){
//方法体
}
}
//表示请求地址为/haha/hello才可访问到此方法,若只使用/hello访问不到此方法
- method属性:限定请求方式,只有请求使用的是method属性限定的方式才可以访问到此方法
3.produces属性:指定响应内容的类型,相当于规定响应头的Content - type
4. headers属性:规定请求头,用法:headers={“xxx”},请求头满足此属性才可以执行此方法
5. consumes属性:只接受内容为指定类型的请求,相当于规定请求头中的Content - type
- @PathVariable注解的使用
@RequestMapping注解的路径上可以使用占位符,用法:将某一层路径写为{变量名},如:
@RequestMapping("/user/{id}") 表示请求地址为/user/xxx访问到的是此方法
@PathVariable注解就是获取这个占位符的值
@RequestMapping("/user/{id}")
public String pathVariableTest(@PathVariable("id")String id){
System.out.println("路径上的占位符的值"+id);
return "xxx";
}
//当浏览器的地址为/user/abc时,输出:路径上的占位符的值abc
- Resultful风格
用请求方式来区分对一个资源是CRUD中的哪一种:
如果是GET请求方式-----查询
如果是PUT请求方式------更新
如果是DELETE请求方式-----删除
如果是POST请求方式-----添加
步骤:
- 使用的时候需要配置一个过滤器
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<!-- 拦截所有请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
- 在index.jsp页面上进行配置
<!-- 发送GET请求 -->
<form action="book/1" method="get">
<input type="submit" value="查询"/>
</form><br/>
<!-- 发送POST请求 -->
<form action="book/1" method="post">
<input type="submit" value="添加"/>
</form><br/>
<!-- 发送DELETE请求 -->
<form action="book/1" method="post">
<input name="_method" value="delete"/>
<input type="submit" value="删除"/>
</form><br/>
<!-- 发送PUT请求 -->
<form action="book/1" method="post">
<input name="_method" value="put"/>
<input type="submit" value="更新"/>
</form><br/>
- 在controller类上进行配置
@Controller
public class BookController {
//处理查询请求
@RequestMapping(value="/book/{bid}",method=RequestMethod.GET)
public String getBook(@PathVariable("bid")Integer id) {
System.out.println("查询到了"+id+"号图书");
return "xxx";
}
//处理删除请求
@RequestMapping(value="/book/{bid}",method=RequestMethod.DELETE)
public String deleteBook(@PathVariable("bid")Integer id) {
System.out.println("删除了"+id+"号图书");
return "xxx";
}
//处理更新请求
@RequestMapping(value="/book/{bid}",method=RequestMethod.PUT)
public String updateBook(@PathVariable("bid")Integer id) {
System.out.println("更新了"+id+"号图书");
return "xxx";
}
//处理添加请求
@RequestMapping(value="/book",method=RequestMethod.POST)
public String addBook() {
System.out.println("添加了新的图书");
return "xxx";
}
}
- 如果出现了报错信息,那么需要在jsp页面的首部进行添加
- 自动封装类型使用
- 写出User类
package com.domain;
public class User {
private String userName;
private String password;
private Integer age;
public User() {
}
public User(String userName, String password, Integer age) {
this.userName = userName;
this.password = password;
this.age = age;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
", age=" + age +
'}';
}
}
2.配置一个index.jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/addToList" method="post">
姓名:<input name="userName" type="text"> <br />
密码:<input name="password" type="password"> <br>
年龄:<input name="age" type="text"> <br>
<input type="submit" value="提交">
<input type="reset" value="取消">
</form>
</body>
</html>
3.写出controller类
package com.controller;
import com.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
/*
进行前端页面数据的接受
*/
@RequestMapping("/addToList")
public String userView(User user, Model model){
model.addAttribute("age", user.getAge());
model.addAttribute("password",user.getPassword());
model.addAttribute("userName", user.getUserName());
return "UserView";
}
}
- 运行并查看结果
- 参数传递问题
@RequestParam注解:此注解用来获取请求参数的值,默认情况下注解中声明的参数请求中必须携带,否则报错
方法中的注解表示:String username = request.getParameter(“user”);
对比一下:
@RequestParam获取的是请求参数的值 (地址中?之后的内容)
@PathVariable获取的是请求路径的值 (地址中?之前的内容)
- 解决中文乱码问题
我们会在web.xml文件中配置一个过滤器进行配置。
- 拦截器调用
SpringMVC提供了拦截器HandlerInterceptor,允许目标方法执行之前进行一些拦截工作,或者目标 方法执行之后进行一些其他处理
HandlerInterceptor是一个接口,其中的方法:
preHandle:目标方法执行之前自动调用;返回true,允许执行目标方法,返回false,不允许执 行目标方法
postHandle:目标方法执行之后自动调用
afterCompletion:整个请求过程完成,来到目标页面之后自动调用
- 返回值类型为ModelAndView类型
public ModelAndView mov1(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg","消息");
modelAndView.setViewName("HelloWorld");
return modelAndView;
}
- 重定向和转发
情况1:
情况2:
情况3:
- 文件上传
index.jsp
<form method="post" enctype="multipart/form-data" action="/upload">
用户头像:<input type = "file" name = "headerimg"/> <br/>
用户名:<input type = "text" name = "username"/> <br/>
<input type = "submit"/>
</form>
dispatch-servlet.xml
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 限制文件大小为20MB -->
<property name="maxUploadSize" value="#{1024 * 1024 * 20}"></property>
<!-- 设置默认编码格式 -->
<property name="defaultEncoding" value="utf-8"></property>
</bean>
controller
@Controller
public class FileUploadController {
//MultipartFile封装了当前文件的信息
public String upload(String username, Model model, @RequestParam("headerimg") MultipartFile file) {
//transferTo将文件下载到磁盘中
//getOriginalFilename得到文件的名称
try {
//上传正常的情况
file.transferTo(new File("G:\\haha\\" + file.getOriginalFilename()));
model.addAttribute("msg", "文件上传成功!");
}catch (IOException e) {
//上传出错的情况
model.addAttribute("msg", "文件上传失败!" + e.getMessage());
}
return "forward:/index.jsp";
}
}
- 异常处理
全局异常
- 使用SimpleMappingExceptionResolver
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<-- 默认的异常界面,如果不是特殊指定的异常,都显示这个界面 -->
<property name="defaultErrorView" value="/exception/handle/errorGlobal" />
<-- 异常的名称,界面上可以使用这个来输出异常信息 -->
<property name="exceptionAttribute" value="e" />
<-- 指定特殊异常,并为特殊异常指定特定的界面 -->
<property name="exceptionMappings">
<props>
<prop
key="xyz.zeling.exception.handle.modules.exception.handle.UserNotFoundException">/exception/handling/errorUser</prop>
</props>
</property>
</bean>
- @ResponseStatus方法
自定义类异常
//value属性指定状态码
@ResponseStatus(reason="用户被拒绝登陆",value=HttpStatus.NOT_ACCEPTABLE)
public class UserNameNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
}
创建一个处理器方法
@RequestMapping("/handle02")
public String handle02(@RequestParam("username") String username) {
if (!"admin".equals(username)) {
throw new UserNameNotFoundException();
//如果出现异常会跳转至此异常指定的页面
}
return "success";
}
- @ExceptionHandler注解的使用
//注解中写上用来处理哪一种异常,多个用逗号隔开
@ExceptionHandler(value = { NullPointerException.class })
//方法中参数的异常对象用来接收发生的异常
public ModelAndView handleException01(Exception exception) {
//myerror是自定义的jsp页面(展示错误信息)
ModelAndView view = new ModelAndView("myerror");
view.addObject("ex", exception);
return view; //出异常之后会跳转到自定义页面,而不是servlet的错误页面
}
//第二个处理异常的方法
@ExceptionHandler(value = { Exception.class })
public ModelAndView handleException02(Exception exception) {
//执行其中的方法
}
//注:当类中有多个方法处理异常时,异常类型越精确的越优先
- 静态资源的处理:
在使用SSM框架做web开发时,遇到SpringMVC拦截了静态资源(如js,css,img等文件),导致jsp页面在浏览器上不能正常显示。
第一种方式:
<mvc:default-servlet-handler/>
第二种方式:
2、springmvc的代码书写
公共部分:
- 导入spring有关的jar:因为是idea创建,会自动下载有关的jar包。
- 修改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">
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 修改dispatch-servlet.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns: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">
<!-- 添加包扫描-->
<context:component-scan base-package="com.controller"/>
<!-- 开启注解-->
<mvc:annotation-driven/>
<!-- 拦截静态资源-->
<mvc:default-servlet-handler/>
<!-- 配置视图解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
2.1、我们创建一个简单的springmvc代码
- 创建一个controller类
@Controller
public class HelloController {
@RequestMapping("/hello1")
public String sayHello1(){
System.out.println("这个是hello1的处理器");
return "index";
}
}
- 运行、查看结果
2.2、我们点击一个按钮或超链接跳转到一个页面中
- 创建一个demo2.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/demo2_in">点我</a>
<form action="${pageContext.request.contextPath}/demo2_out">
<input type="submit" value="提交">
</form>
</body>
</html>
- 编写controller类
package com.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class Demo2 {
@RequestMapping("/demo2_in")
public String in(){
System.out.println("这个是超链接跳转的结果");
return "demo2_in";
}
@RequestMapping("/demo2_out")
public String out(){
System.out.println("这个是form表单跳转的结果");
return "demo2_out";
}
}
- 编写结果jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
这个是超链接返回的结果
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
这个是form表单跳转的 结果
</body>
</html>
- 查看结果
2.3、编写一个接受参数并返回给页面的代码
- 编写输入的jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/addToList" method="post">
姓名:<input name="userName" type="text"> <br />
密码:<input name="password" type="password"> <br>
年龄:<input name="age" type="text"> <br>
<input type="submit" value="提交">
<input type="reset" value="取消">
</form>
</body>
</html>
- 编写controller类,实体类与之对应
package com.domain;
public class User {
private String userName;
private String password;
private Integer age;
public User() {
}
public User(String userName, String password, Integer age) {
this.userName = userName;
this.password = password;
this.age = age;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
", age=" + age +
'}';
}
}
package com.controller;
import com.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
/*
进行前端页面数据的接受
*/
@RequestMapping("/addToList")
public String userView(User user, Model model){
model.addAttribute("age", user.getAge());
model.addAttribute("password",user.getPassword());
model.addAttribute("userName", user.getUserName());
return "UserView";
}
}
- 编写结果页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>这个是userView的界面</h1>
姓名:${userName}
年龄:${age}
密码:${password}
</body>
</html>
- 查看运行结果
2.4、拦截器的使用
- 创建拦截器类
package com.intercept;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FirstIntercept implements HandlerInterceptor {
@Override
public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
}
- 注册拦截器(dispatch-servlet.xml)
<!-- 配置拦截器-->
<mvc:interceptors>
<bean class="com.intercept.FirstIntercept"></bean>
</mvc:interceptors>
- 查看结果