SpringMVC
Posted chn-tiancx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVC相关的知识,希望对你有一定的参考价值。
SpringMVC
说明下【本文是在网上听课做的笔记,代码是自己敲的,有些文字是复制的老师发的】
SpringMVC概述
使用SpringMVC替换Servlet
Servlet的问题:
1、需要判断调用哪个方法。(逻辑需要自己编写)
2、需要获得request的数据,并且需要手动封装,还要进行类型转换。
3、跳转和转发数据的代码太繁琐。
4、通过ajax请求的对象,需要通过fastjson进行转换,并使用相应对象的输出流写出。
以上问题SpringMVC都给出了解决方案。
1、添加依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
2、在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>
<!--
前端控制器
-->
<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:springMVC-Servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!--
/表示拦截了除了jsp之外所有的请求
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3、编写SpringMVC的配置文件(结构和Spring配置文件一致)
<?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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--
映射器
-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<!--
适配器
-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--
视图解析器
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/" />
<property name="suffix" value=".jsp"/>
</bean>
<!--
配置Controller
-->
<!-- <bean id="/user" class="com.woniu.controller.UserController"></bean>-->
<bean id="/user" class="cn.cqie.controller.UserController"/>
</beans>
4、添加Controller
package cn.cqie.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/23 21:30
*/
public class UserController implements Controller {
@Override
public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
System.out.println("UserController.handleRequest");
return null;
}
}
5、通过浏览器访问Controller
SpringMVC的工作机制
DispatcherServlet
<?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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--
映射器
BeanNameUrlHandlerMapping
在浏览器中发送/user
通过/user在Spring容器中找到id对应的实例
SimpleUrlHandlerMapping
声明一个映射关系
Properties
-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/user">userController</prop>
</props>
</property>
</bean>
<!--
适配器
SimpleControllerHandlerAdapter
可以执行实现了Controller接口的控制器
HttpRequestHandlerAdapter
可以执行实现了HttpRequestHandler接口的控制器
-->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" ></bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" ></bean>
<!--
视图解析器
prefix 从webapp根目录指定
suffix 是后缀
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--
配置Controller
-->
<bean id="userController" class="cn.cqie.controller.UserController"></bean>
</beans>
Controller的实现
使用注解配置Controller
package cn.cqie.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/23 21:30
*/
@Controller
public class UserController2 {
@RequestMapping("userSave")
public ModelAndView save(){
System.out.println("UserController2.save");
return new ModelAndView("index");
}
}
<?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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="cn.cqie"/>
<mvc:annotation-driven></mvc:annotation-driven> <!--这个可以替换掉下面的两个 bean,甚至更多 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>-->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>-->
<!--
视图解析器
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/" />
<property name="suffix" value=".jsp"/>
</bean>
<!--
配置Controller
-->
<!-- <bean id="/user" class="com.woniu.controller.UserController"></bean>-->
<bean id="userController" class="cn.cqie.controller.UserController"/>
</beans>
ModelAndView类
package cn.cqie.controller;
import cn.cqie.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.ArrayList;
import java.util.List;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/23 21:30
*/
@Controller
public class UserController2 {
// @RequestMapping("testList") 就是在浏览器输入 testList 和以前的servlet一样
@RequestMapping("testList")
public ModelAndView list(){
System.out.println("UserController2.save");
List<User> list =new ArrayList<>();
list.add(new User("yx",26));
list.add(new User("wls",20));
list.add(new User("tcx",20));
// /list.jsp
ModelAndView ma = new ModelAndView("list");
//request.setAttribute();
ma.addObject("msg","66666");
return ma;
}
@RequestMapping("testList2")
public ModelAndView list2(){
System.out.println("UserController2.save");
List<User> list =new ArrayList<>();
list.add(new User("yx",26));
list.add(new User("wls",20));
list.add(new User("tcx",20));
ModelAndView ma = new ModelAndView("list2");
ma.addObject("msg",list);
return ma;
}
@RequestMapping("testList3")
public ModelAndView list3(){
System.out.println("UserController2.save");
List<User> list =new ArrayList<>();
list.add(new User("yx",26));
list.add(new User("wls",20));
list.add(new User("tcx",20));
ModelAndView ma = new ModelAndView("list2");
//request.setAttribute(); 名字默认为类型与泛型的组合 userList
ma.addObject(list);
return ma;
}
@RequestMapping("testList4")
public String list4(Model model){
System.out.println("UserController2.save");
List<User> list =new ArrayList<>();
list.add(new User("yx",26));
list.add(new User("wls",20));
list.add(new User("tcx",20));
model.addAttribute(list);
return "list2"; // /list.jsp
}
@RequestMapping("testList5")
public String list5(Model model){
//重定向
return "redirect:list.jsp";
}
}
相关的jsp页面
list.jsp
<%--
Created by IntelliJ IDEA.
User: admin
Date: 2021/11/24
Time: 21:08
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
list2.jsp
<%--
Created by IntelliJ IDEA.
User: admin
Date: 2021/11/24
Time: 21:15
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<ul>
<c:forEach items="${userList}" var="user">
<li>${user.name}</li>
</c:forEach>
</ul>
</body>
</html>
jstl需要导入的依赖
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
视图解析器概述
将Controller的返回值进行解析,到浏览器。
在SpringMVC中也有很多视图解析器
这时通过视图解析器解析handler返回的值(逻辑视图,转发数据)
InternalResourceViewResolver会将逻辑视图与prefix和suffix组合成物理视图名,
如果逻辑视图返回值中包含redirect:,则进行重定向操作,如果是forward:或者没有前缀,则转发操作。
编写一个视图
package cn.cqie.controller.a_view;
import org.springframework.web.servlet.View;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/25 15:02
*/
public class MyView implements View {
@Override
public String getContentType() {
return null;
}
@Override
public void render(Map<String, ?> map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//map就是model中添加的数据
for (Map.Entry<String, ?> entry : map.entrySet()) {
httpServletRequest.setAttribute(entry.getKey(), entry.getValue());
System.out.println(" "+entry.getKey()+" : " +entry.getValue());
}
System.out.println("MyView.render");
httpServletRequest.getRequestDispatcher("abc.jsp").forward(httpServletRequest, httpServletResponse);
}
}
<?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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="cn.cqie.controller.a_view"/>
<mvc:annotation-driven/>
<!--
BeanNameViewResolver是当前项目的中视图解析器
MyView声明了跳转的方式和数据转发
-->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"></bean>
<bean id="myView" class="cn.cqie.controller.a_view.MyView"></bean>
</beans>
package cn.cqie.controller.a_view;
import cn.cqie.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/23 21:30
*/
@Controller
public class UserController {
@RequestMapping("save")
public String save(Model model){
System.out.println("UserController.save");
User xy = new User("xy", 30);
model.addAttribute("a",xy);
return "myView";
}
}
请求映射
1、RequestMapping可以声明在类和方法上
RequestMapping
可以声明在类上,如果要访问方法,需要将类的RequestMapping的值与方法上的RequestMapping的值组合访问。
为了防止直接通过浏览器访问jsp页面,将所有页面放到WEB-INF下。只能通过控制器跳转。在视图解析器中的前缀添加WEB-INF。
2、可以根据不同的请求方式来控制哪种请求可以访问
//method = RequestMethod.POST只有页面通过post传参,才可以访问到这个方法
@RequestMapping(value = "save",method = RequestMethod.POST)
public String save(){
System.out.println("UserController.save");
return "b";
}
浏览器地址栏访问 都是Get请求
3、在RequestMapping中添加params
//页面需要传递params中声明的参数,且值必须相等,这时才可以访问该方法
@RequestMapping(value = "login",params = {"uname=admin","pwd=123"})
public String login(String uname,String pwd){//这里要和 地址栏里面的参数一致才行 uname与uname对应 要对应
System.out.println("UserController.save2");
System.out.println(uname+" "+pwd);
return "b";
}
4、在RequestMapping中添加Headers
//可以在RequestMapping中声明headers,获得页面传递的请求头,从请求头中获得对应的信息,如果该信息相等,允许访问该方法
@RequestMapping(value = "list",headers = "host=localhost:8080")
//headers = "host=localhost:8080"只允许本机访问 。 【注意】 127.0.0.1 也不行必须 localhost
public String list(){
System.out.println("UserController.list");
return "b";
}
5、在RequestMapping中添加占位符
@RequestMapping(value = "login2/{uname}/{pwd}")
//需要使用注解
public String login2(@PathVariable("uname") String uname,@PathVariable("pwd") String pwd){
System.out.println("UserController.save2");
System.out.println(uname+" "+pwd);
return "b";
}
相应的配置文件
<?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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="cn.cqie.controller.b_request_mapping"/>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
相关内容
控制器方法入参
1、基本数据类型的自动转化
2、自动封装数据
package cn.cqie.controller.c_param;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import java.util.Arrays;
import java.util.List;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/23 21:30
*/
@Controller
public class UserController {
/**
* 在SpringMVC的Controller中不再需要request.getParameter(),直接在方法的参数中声明即可,要求参数名与表单控件的name一致
* 如果非要不一致,则需要添加注解@RequestParam("表单的name值")
*/
@RequestMapping("save1")
public String save1(String name,@RequestParam("pwd") String password){
System.out.println("UserController.save1:"+name+" : "+password);
return null;
}
//SpringMVC的Controller,可以对数据进行自动转换
@RequestMapping("save2")
public String save2(Integer age){
System.out.println("UserController.save2: "+(2021-age));//输出年份
return null;
}
//可以将表单的数据自动封装成对象(参数中指定的类型)
@RequestMapping("save3")
public String save3(User user){
System.out.println("UserController.save3: "+user);
return null;
}
//复选框的值可以直接获得为字符串数据,整型数组,如果需要List<Integer>类型,则需要添加注解@RequestParam
// @RequestMapping("save4")
// public String save4(String[] ids){
// System.out.println("UserController.save4: ");
// System.out.println(Arrays.toString(ids));
// return null;
// }
@RequestMapping("save4")
public String save4(@RequestParam List<Integer> ids){
System.out.println("UserController.save4: ");
System.out.println(ids);
return null;
}
}
<%--
Created by IntelliJ IDEA.
User: admin
Date: 2021/11/25
Time: 17:18
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>传递参数到Controller</h3>
<form action="save1" method="post">
<input name="name">
<input name="pwd">
<button>submit</button>
</form>
<hr>
<h3>传递整型数据</h3>
<form action="save2">
<input name="age">
<button>submit</button>
</form>
<hr>
<h3>传递对象数据</h3>
<form action="save3">
<input name="name">
<input name="age">
<button>submit</button>
</form>
<hr>
<h3>传递复选框数据</h3>
<form action="save4">
<input type="checkbox" name="ids" value="1">
<input type="checkbox" name="ids" value="2">
<input type="checkbox" name="ids" value="3">
<button>submit</button>
</form>
</body>
</html>
时间类型参数
SpringMVC中默认识别日期格式为yyyy/MM/dd
其他格式需要自己编写转换类
package cn.cqie.controller.d_convert;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/25 21:31
*/
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String s) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
//还可以转换其他的, 比如 yyyy.MM.dd
Date date = null;
try {
//将日期转换成字符串
date= simpleDateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
将转换类配置到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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="cn.cqie.controller.d_convert"/>
<mvc:annotation-driven conversion-service="conversionService"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.cqie.controller.d_convert.DateConverter"></bean>
</set>
</property>
</bean>
</beans>
Controller里面的代码
package cn.cqie.controller.d_convert;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.Date;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/23 21:30
*/
@Controller
public class UserController {
@RequestMapping("save1")
public String save(Date date){
System.out.println(date);
return null;
}
}
使用ServletAPI
HttpServletRequest
HttpServletResponse
HttpSession
ServletContext
HttpServletRequest,HttpServletResponse,HttpSession对象都可以从方法参数中获取
@RequestMapping("login")
public String login(HttpServletRequest req, HttpServletResponse resp, HttpSession session){
System.out.println("HttpServletRequest"+req);
System.out.println("HttpServletResponse"+resp);
System.out.println("HttpSession"+session);
return null;
}
SpringMVC数据校验
正则表达式
电话号码格式
邮箱格式
身份证格式等等
前端数据校验 (可以减轻服务器压力)
后端数据校验
1、添加依赖
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.20.Final</version>
</dependency>
2、定义校验规则
在封装类上定义校验规则,JSR303
package cn.cqie.controller.e_validator;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/24 21:04
*/
public class User implements Serializable {
//null ""
// 在封装类上定义校验规则,JSR303
// @NotBlank(message = "uname 不能为空!")
@NotBlank(message = "name 不能为空")
private String name;
@NotNull(message = "age 不能为空")
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "User{" +
"name=\'" + name + \'\\\'\' +
", age=" + age +
\'}\';
}
}
3、对需要校验的数据添加注解 @Validated
package cn.cqie.controller.e_validator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/23 21:30
*/
@Controller
public class UserController {
@RequestMapping("save")
public String save(@Validated User user, Errors errors, Model model){
System.out.println("UserController.save");
List<FieldError> fieldErrors = errors.getFieldErrors();
for( FieldError fieldError:fieldErrors){
System.out.println(fieldError.getField()+" "+fieldError.getDefaultMessage());
model.addAttribute(fieldError.getField()+"msg",fieldError.getDefaultMessage());
}
if(fieldErrors.size()!=0) return "e";
return null;
}
}
4、在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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="cn.cqie.controller.e_validator"/>
<mvc:annotation-driven validator="validator" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
</bean>
</beans>
SpringMVC集成JSON
1、添加依赖
将对象或者集合转换成json
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<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-annotations</artifactId>
<version>2.9.0</version>
</dependency>
2、在方法上添加注解@ResponseBody
package cn.cqie.controller.f_ajax;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.ArrayList;
import java.util.List;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/23 21:30
*/
@Controller
public class UserController{
@RequestMapping("list")
@ResponseBody //返回的对象交给jackson-databind进行转json并输出的操作
public List<User> list(){
System.out.println("UserController.list");
List<User> list = new ArrayList<>();
list.add(new User("yx",26));
list.add(new User("tcx",20));
return list;
}
@RequestMapping("save")
@ResponseBody
public String save(@RequestBody User user){
System.out.println("UserController.save");
System.out.println(user);
return "ok";
}
}
要求页面传递数据格式为json
- data:JSON.stringify(jsonStr)
在Controller方法上添加注解@RequestBody
- public String save(@RequestBody User user)
因为默认按照键值对解析数据
- contentType:"application/json"
可以使用POSTMAN进行测试
f.jsp
<%--
Created by IntelliJ IDEA.
User: admin
Date: 2021/11/25
Time: 17:18
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
</head>
<body>
<form >
<input type="text" name="name" id="name">
<input type="text" name="age" id="age">
<button id="btnSave">btnSave</button>
</form>
</body>
<script>
$(document).ready(function (){
$(\'#btnSave\').click(function (){
var jsonStr = {\'name\':$(\'#name\').val(),\'age\':$(\'#age\').val()}
alert(JSON.stringify(jsonStr))
$.ajax({
url : "save",
type : "post",
contentType : "application/json",
data:JSON.stringify(jsonStr),
success:function(data){
alert(data);
}
});
});
});
</script>
</html>
postMan工具的使用
RESTful
RESTful概念
REST(英文:Representational State Transfer,简称REST)
表述性状态转移; 表现状态传输;
描述了一个架构样式的网络系统,比如 web 应用程序。它首次出现在 2000 年 Roy Fielding 的博士论文中,Roy Fielding是 HTTP 规范的主要编写者之一。
在目前主流的三种Web服务交互方案中,REST相比于SOAP(Simple Object Access protocol,简单对象访问协议)以及XML-RPC更加简单明了,无论是对URL的处理还是对Payload的编码,REST都倾向于用更加简单轻量的方法设计和实现。值得注意的是REST并没有一个明确的标准,而更像是一种设计的风格。
特点
RESTFUL特点包括:
1、每一个URI代表1种资源;
2、客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;
3、通过操作资源的表现形式来操作资源;
4、资源的表现形式是XML或者HTML;
5、客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。
RESTful资源设计规则
URI
URI 表示资源,资源一般对应服务器端领域模型中的实体类。
URI规范
不用大写;
用中杠-不用下杠_;
参数列表要encode;
URI中的名词表示资源集合,使用复数形式。
资源集合 vs 单个资源
URI表示资源的两种方式:资源集合、单个资源。
资源集合:
/zoos //所有动物园
/zoos/1/animals //id为1的动物园中的所有动物
单个资源:
/zoos/1 //id为1的动物园
/zoos/1;2;3 //id为1,2,3的动物园
避免层级过深的URI
/在url中表达层级,用于按实体关联关系进行对象导航,一般根据id导航。
过深的导航容易导致url膨胀,不易维护,如 GET /zoos/1/areas/3/animals/4,尽量使用查询参数代替路径中的实体导航,如GET /animals?zoo=1&area=3;
对Composite资源的访问
服务器端的组合实体必须在uri中通过父实体的id导航访问。
组合实体不是first-class的实体,它的生命周期完全依赖父实体,无法独立存在,在实现上通常是对数据库表中某些列的抽象,不直接对应表,也无id。一个常见的例子是 User — Address,Address是对User表中zipCode/country/city三个字段的简单抽象,无法独立于User存在。必须通过User索引到Address:GET /user/1/addresses
- Request
HTTP方法
通过标准HTTP方法对资源CRUD:
GET:查询
GET /zoos
GET /zoos/1
GET /zoos/1/employees
POST:创建单个资源。POST一般向“资源集合”型uri发起
POST /animals //新增动物
POST /zoos/1/employees //为id为1的动物园雇佣员工
PUT:更新单个资源(全量),客户端提供完整的更新后的资源。与之对应的是 PATCH,PATCH 负责部分更新,客户端提供要更新的那些字段。PUT/PATCH一般向“单个资源”型uri发起
PUT /animals/1
PUT /zoos/1
DELETE:删除
DELETE /zoos/1/employees/2
DELETE /zoos/1/employees/2;4;5
DELETE /zoos/1/animals //删除id为1的动物园内的所有动物
Controller.java
package cn.cqie.controller.g_rest;
import cn.cqie.controller.f_ajax.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/23 21:30
*/
@Controller
@RequestMapping("users")
public class UserController {
//get请求都是做查询操作
//使用get请求http://localhost:8080/projectname/users
// @RequestMapping(method = RequestMethod.GET)
@GetMapping
public String findAll(){
System.out.println("UserController.findAll");
return null;
}
//使用get请求http://localhost:8080/projectname/users/1
// @RequestMapping(value = "{id}",method = RequestMethod.GET)
@GetMapping(value = "{id}")
public String findOne(@PathVariable Integer id){
System.out.println("UserController.findOne: "+id);
return null;
}
//post请求做新增操作
// @RequestMapping(method = RequestMethod.POST)
@PostMapping
public String save(User user){
System.out.println("UserController.save: "+user);
return null;
}
//put请求做修改操作
// @RequestMapping(method = RequestMethod.PUT)
@PutMapping
public String update(User user){
System.out.println("UserController.update: "+user);
return null;
}
//delete请求做删除操作
// @RequestMapping(value = "{id}",method = RequestMethod.DELETE)
@DeleteMapping(value = "{id}")
public String delete(@PathVariable Integer id){
System.out.println("UserController.delete: "+id);
return null;
}
}
g.jsp
<%--
Created by IntelliJ IDEA.
User: admin
Date: 2021/11/25
Time: 17:18
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
</head>
<body>
<form action="users" method="post">
<input type="text" name="name">
<input type="text" name="age">
<button id="btnSave">btnSave</button>
</form>
<hr>
<form action="users" method="post">
<!--
如果要做put请求:
1.需要添加隐藏域,声明put请求
2.使用一个过滤器读取隐藏域信息,完成put请求
-->
<input type="hidden" name="_method" value="put">
<input type="text" name="name">
<input type="text" name="age">
<button id="update">update</button>
</form>
<hr>
<form action="users/9" method="post">
<input type="hidden" name="_method" value="delete">
<button id="delete">delete</button>
</form>
</body>
</html>
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>
<!--
RESTful风格中过滤请求方式(put,delete)
-->
<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>
<!--
前端控制器
-->
<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:g_rest/springMVC-Servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!--
/表示拦截了除了jsp之外所有的请求
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
要在web.xml中添加过滤器
<!--
RESTful风格中过滤请求方式(put,delete)
-->
<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>
小技巧:@RequestMapping 可以替换 (get post put update delete)
// @RequestMapping(method = RequestMethod.GET) @GetMapping // @RequestMapping(value = "{id}",method = RequestMethod.GET) @GetMapping(value = "{id}") // @RequestMapping(value = "{id}",method = RequestMethod.DELETE) @DeleteMapping(value = "{id}")
技巧:
@Controller 替换成 @RestController 可以直接返回 JSON数据
处理静态资源
1)采用<mvc:default-servlet-handler />
在springMVC-servlet.xml中配置<mvc:default-servlet-handler />后,会在Spring MVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它会像一个检查员,对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。
一般Web应用服务器默认的Servlet名称是"default",因此DefaultServletHttpRequestHandler可以找到它。如果你所有的Web应用服务器的默认Servlet名称不是"default",则需要通过default-servlet-name属性显示指定:
<mvc:default-servlet-handler default-servlet-name="所使用的Web服务器默认使用的Servlet名称" />
2)采用<mvc:resources />
<mvc:default-servlet-handler />将静态资源的处理经由Spring MVC框架交回Web应用服务器处理。而<mvc:resources />更进一步,由Spring MVC框架自己处理静态资源,并添加一些有用的附加值功能。
首先,<mvc:resources />允许静态资源放在任何地方,如WEB-INF目录下、类路径下等,你甚至可以将JavaScript等静态文件打到JAR包中。通过location属性指定静态资源的位置,由于location属性是Resources类型,因此可以使用诸如"classpath:"等的资源前缀指定资源位置。传统Web容器的静态资源只能放在Web容器的根路径下,<mvc:resources />完全打破了这个限制。
其次,<mvc:resources />依据当前著名的Page Speed、YSlow等浏览器优化原则对静态资源提供优化。你可以通过cacheSeconds属性指定静态资源在浏览器端的缓存时间,一般可将该时间设置为一年,以充分利用浏览器端的缓存。在输出静态资源时,会根据配置设置好响应报文头的Expires 和 Cache-Control值。
在接收到静态资源的获取请求时,会检查请求头的Last-Modified值,如果静态资源没有发生变化,则直接返回303相应状态码,提示客户端使用浏览器缓存的数据,而非将静态资源的内容输出到客户端,以充分节省带宽,提高程序性能。
<?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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="cn.cqie.controller.g_rest"/>
<mvc:annotation-driven />
<!-- <mvc:default-servlet-handler></mvc:default-servlet-handler>-->
<mvc:resources mapping="/img/**" location="/img/"></mvc:resources>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
SpringMVC拦截器
1、编写一个拦截器
package cn.cqie.controller.h_interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/29 20:52
*/
public class LoginInterceptor implements HandlerInterceptor {
/**
* 在handle执行之前
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("LoginInterceptor.preHandle");
//如果return true则放行
return true;
}
/**
* 在handle执行之后
*/
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("LoginInterceptor.postHandle");
}
// 在视图解析之后
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("LoginInterceptor.afterCompletion");
}
}
2、配置拦截器
<?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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="cn.cqie.controller.h_interceptor"/>
<mvc:annotation-driven />
<!--
配置拦截器栈
-->
<mvc:interceptors>
<!--
配置拦截器
-->
<mvc:interceptor>
<!--
配置拦截规则
-->
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/login"/>
<!--
拦截器对象
-->
<bean class="cn.cqie.controller.h_interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
controller.java
package cn.cqie.controller.h_interceptor;
import org.springframework.web.bind.annotation.*;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/23 21:30
*/
@RestController
public class UserController {
@RequestMapping("list")
public String list(){
System.out.println("UserController.list");
return null;
}
@RequestMapping("login")
public String login(){
System.out.println("UserController.login");
return null;
}
}
SpringMVC文件上传
1、表单
<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="photo">
<button>uploade</button>
</form>
</body>
</html>
2、添加依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
3、上传的操作
package cn.cqie.controller.i_upload;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/23 21:30
*/
@Controller
public class UserController {
@RequestMapping("upload")
public String upload(MultipartFile photo,HttpServletRequest request){
//声明一个指定目录,用来存放上传的文件
String realPath = request.getServletContext().getRealPath("/upload");
System.out.println("UserController.upload: "+realPath);
File dir = new File(realPath);
if(!dir.exists()){
dir.mkdirs();
}
//每个上传的文件名不重复UUID, 当前时间的毫秒数
String filename = photo.getOriginalFilename(); //getName获取的是控件的名字
String suffix = filename.substring(filename.lastIndexOf("."));
filename = UUID.randomUUID() + suffix;
System.out.println("UserController.upload: "+photo.getName());
try {
photo.transferTo(new File(dir,filename));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
4、上传解析器
<?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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="cn.cqie.controller.i_upload"/>
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--必须添加id,否则会导致上传不成功-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"></property>
<property name="maxUploadSize" value="20000000"></property>
</bean>
</beans>
SpringMVC异常处理
1、编写异常处理类
package cn.cqie.controller.j_exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/30 11:44
*/
@ControllerAdvice
public class ExceptionHandlerDemo implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
System.out.println("ExceptionHandlerDemo.resolveException: "+o.getClass());
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
modelAndView.addObject("message",e.getMessage());
return modelAndView;
}
}
2、编写异常展示页面
<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
</head>
<body>
${message}
</body>
</html>
3、编写Controller生成异常
package cn.cqie.controller.j_exception;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
/**
* Description:
* Author: tiancx
* Date: Created in 2021/11/23 21:30
*/
@Controller
public class UserController {
@RequestMapping("test/{num}")
public String test(@PathVariable("num") Integer num){
System.out.println("UserController.test: "+10/num);
return null;
}
}
本文来自博客园,作者:chn-tiancx,转载请注明原文链接:https://www.cnblogs.com/tiancx/p/15663082.html
以上是关于SpringMVC的主要内容,如果未能解决你的问题,请参考以下文章
Spring Rest 文档。片段生成时 UTF-8 中间字节无效 [重复]