已同步微信公众号
乐享Coding
,获取更多Java学习资源,技术交流群
期待你的关注!
SpringMVC总结整理
web开发底层是servlet,框架是在servlet基础上面加一些功能,方便web开发。
SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品。它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。同时还支持Restful编程风格的请求。
将应用程序分为Controller,Model,View三层,Controller接收用户请求,调用Model生成业务数据,传递给View。
核心组件
前端控制器
(DispatcherServlet)
-
**【总指挥】**负责接收用户的提交的所有请求,如传统的jsp文件,调用其他的控制器Controller对象,并把请求处理的结果显示给用户。
// 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">
<!--配置DispatchServlet,MVC核心,前端控器器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--通过初始化参数指定SpringMVC配置文件的位置,进行关联-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring_mvc.xml</param-value> <!-- classpath:指resource根目录 -->
</init-param>
<!-- 启动顺序,数字越小,启动越早 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern> <!-- 拦截所有请求 -->
</servlet-mapping>
</web-app>
处理器
(Handler)
-
完成具体的业务逻辑,相当于servlet或action。
// 就是一个方法
请求到处理器映射
(HandlerMapping)
-
DispatcherServlet接收到请求之后,通过HandlerMapping将不同的请求映射到不同的请求映射到不同的Handler。
// @RequestMapping注解将URL请求与业务方法(Handler)映射
处理器适配器
(HandlerAdapter)
- Handler执行业务方法之前,需要进行一系列的操作,如表单数据的验证,数据类型的转换,将表单数据封装成JavaBean等,因此开发者只需将注意力集中到业务逻辑的处理上,DispatcherServlet通过HandlerAdapter执行不同的Handler。
视图解析器
(ViewResolver)
-
DispatcherServlet通过它将逻辑视图转换为物理视图,最终将渲染结果响应给客户端。
// resource文件夹下spring_mvc.xml配置视图解析器
<!--xml视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀 value属性指的是web文件夹的根目录-->
<property name="prefix" value="/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
处理器拦截器
(HandlerInterceptor)
- 是一个接口,如果需要完成拦截处理,实现该接口。
处理器执行链
(HandlerExecutionChain)
- 处理器执行链,包含两部分,HandlerInterceptor和Handler
ModelAndView
装载了模型数据和视图信息,作为Handler的处理结果(业务方法返回ModelAndView
对象),之后返回给DispatcherServlet做下一步处理。
工作流程
- 客户端请求被DispatcherServlet接收。
- 根据HandlerMapping映射到Handler。
- 生成Handler和HandlerInterceptor。
- Handler和HandlerInterceptor以HandlerExecutionChain的形式一并返回给DispatcherServlet。
- DispatcherServlet通过HandlerAdapter调用Handler的方法完成业务逻辑处理。
- Handler返回一个ModerAndView对象给DispatcherServlet。
- DispatcherServlet将获取的ModerAndView对象传给ViewResolver视图解析,将逻辑视图解析为物理视图View。
- ViewResolver返回一个View给DispatcherServlet。
- DispatcherServlet根据View进行视图渲染(将模型数据Model填充到视图View中)
- DispatcherServlet将渲染后的结果响应给客户端。
实际开发
流程非常复杂,实际开发中使用极其简单,因为大部分的组件不需要开发者创建,管理,只需要通过配置文件的方式完成配置即可,真正需要开发者进行处理的只有Handler,View。
Tomcat运行配置
打war包
-
IDEA中按快捷键ctrl+alt+shift+s打开project Structure
-
之后在tomcat中配置war包启动
注意
每次pom.xml中导入新的依赖,需要看war包中是否也导入成功了,有时会没有导入就手动添加上。
中文乱码问题
前端发起请求后端收到却包含中文乱码
- 解决办法,只需在web.xml配置SpringMVC自带的过滤器即可。
<!--配置SpringMVC自带的过滤器解决乱码问题-->
<filter>
<filter-name>encodingFilter</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>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
后端响应前端JSON数据时乱码
- 解决办法,spring_mvc.xml配置消息转换器
<mvc:annotation-driven conversion-service="conversionService">
<mvc:message-converters register-defaults="true">
<!--配置消息转换器,解决后台响应数据时中文乱码-->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/html;charset=UTF-8"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
注解
【@RequestMapping】
将URL请求与业务方法进行映射,在Handler的类定义处以及方法定义处都可以添加@RequestMapping。
相关参数
-
value
:指定URL请求的实际地址,是@RequestMapping的默认值。@RequestMapping(value = "/index")
@RequestMapping("/index")
-
method
:指定请求的method类型,GET,POST,PUT,DELET@RequestMapping(value = "/index",method = RequestMethod.GET)
表示只能接受GET请求。
-
params
:指定请求中必须包含某些参数,否则无法调用该方法。@RequestMapping(value = "/index", method = RequestMethod.GET, params = {"name", "id"= 1 })
该代码表示请求中必须包含name和id两个参数,同时id的值必须是1。
方法中可以传递请求中接收的参数,分两种情况
假设是index方法
-
请求参数与形参名称相同
@RequestMapping(value = "/index", method = RequestMethod.GET, params = {"name", "id"= 1 }) public String index(String name,int id) { System.out.println(name+id); return "index"; }
-
请求参数与形参名称不相同【需要加@RequestParam注解进行参数绑定】
@RequestMapping(value = "/index", method = RequestMethod.GET, params = {"name", "id"= 1 }) public String index(@RequestParam("name") String str,@RequestParam("id") int sid) { System.out.println(name+id); return "index"; }
该代码表示将请求的参数name和id分别赋值给了形参str和sid,同时完成了数据类型的转换,将字符串类型“1”转换为了int类型1,再赋给sid,这些工作都是由HandlerAdapter来完成的。
Restful风格的URL
-
传统类型传递参数 http://localhost:8080/index?name=xiaole&id=1
-
Restful传递参数 http://localhost:8080/index/xiaole/1
@RequestMapping("/restful/{name}/{id}") public String restful(@PathVariable("name") String name,@PathVariable("id") int sid) { System.out.println(name+id); return "index"; }
Tips:无论请求参数名和业务方法中形参是否相同,都需要加@PathVariable注解进行映射
-
映射 Cookie
-
Spring MVC通过映射可以直接在业务方法中获取Cookie的值。
@RequestMapping("/cookie") public String cookie(@CookieValue(value = "JSESSIONID") String sessionId) { System.out.println(sessionId); return "index"; }
-
-
使用JavaBean绑定参数
-
Spring MVC 会根据请求参数名和JavaBean属性名进行自动匹配,自动为对象填充属性值,同时支持级联属性(对象中包含对象的属性)
- 实体类 User 和 Address(文件夹Entity)
@Data //必须加,否则接收不到 public class User { private Integer id; private String name; private Address address; //级联属性 }
@Data public class Address { private String value; }
- JSP文件的前端表单
<form action="/hello/save" method="post"> 用户id :<input type="text" name="id"><br> 用户名: <input type="text" name="name"><br> 地址: <input type="text" name="address.value"><br> <%--级联属性--%>html <input type="submit" value="注册"> </form>
- Controller包下的handler类业务方法
@RequestMapping(value = "/hello/save", method = RequestMethod.POST) public String save(User user) { System.out.println(user); return "index"; } @RequestMapping("/hello") public String submit() { return "register"; }
测试地址
:http://localhost:8080/helloTips:需要配置解决乱码(过滤器)
-
-
html页面进行转发和重定向
-
【转发】默认
return "forward:/index"; == return "index";
-
【重定向】
return "redirect:/index";
-
-
-
【@Controller】
在类定义处添加,将该类交给IOC容器来管理(结合springmvc.xml的自动扫描配置使用),同时使其成为一个控制器,使得每一个业务方法的返回值都会交给视图解析器进行解析。
【@Requestbody】
不进行视图解析
在类定义处添加,也可以单独在方法中添加,表示直接将业务方法的返回值响应给客户端,不加的话返回的话,会将返回值传递给DispatcherServlet,再由DispatcherServlet调用ViewResolver对值进行解析,映射到一个jsp资源或html资源。
【@RestController】
@Requestbody+@Controller,在类定义处添加,包含两个注解的功能,即其类下的所有业务方法都不进行解析视图。
数据绑定
在后端的业务方法中直接获取客户端HTTP请求中的参数,将请求的参数映射到业务方法的形参中,Spring MVC中数据绑定的工作是由HandlerAdapter来完成的。
【基本数据类型】
-
@ResponseBody //直接将业务方法的返回值响应给客户端,不需要视图解析 public String base(int id) {}; //业务方法中传基本数据类型int
【包装类】
-
建议使用,因为可以接收null值,当HTTP请求没有参数时,不会抛出异常,基本数据类型不行。
@ResponseBody //直接将业务方法的返回值响应给客户端,不需要视图解析 public String pack(Integer id) {}; //业务方法中传包装类Integer
public String pack(@RequestParam(value = "num",required = false,defaultValue = "10") Integer id) {}; //也可以加@RequestParam注解,required属性是必须加或否,范围布尔值,false情况下可设默认值
【集合】
- 创建userList实体类
@Data
public class userList {
private List<User> userList;
}
- JSP前端页面
<!--List.jsp页面-->
<form action="/list" method="post">
用户1id :<input type="text" name="userList[0].id"><br>
用户1名: <input type="text" name="userList[0].name"><br>
1地址: <input type="text" name="userList[0].address.value"><br> <%--级联属性--%>
用户2id :<input type="text" name="userList[1].id"><br>
用户2名: <input type="text" name="userList[1].name"><br>
2地址: <input type="text" name="userList[1].address.value"><br> <%--级联属性--%>
<input type="submit" value="注册">
</form>
- 业务方法
@RequestMapping("/list")
@ResponseBody
public String submitList(userList userList) {
StringBuffer str= new StringBuffer(); //解决+号影响效率
for (User user:userList.getUserList()
) {
str.append(user);
}
return str.toString();
}
测试地址
:http://localhost:8080/List.jsp
【Map】
- 创建UserMap实体类
@Data
public class UserMap {
private Map<String,User> userMap;
}
- 业务方法
@RequestMapping(value = "/map", method = RequestMethod.POST)
@ResponseBody
public String submitMap(UserMap userMap) {
StringBuffer str = new StringBuffer();
for (String key : userMap.getUserMap().keySet()) {
str.append(userMap.getUserMap().get(key)); //根据key找到value
}
return str.toString();
}
- JSP前端页面
<!--Map.jsp页面-->
<form action="/map" method="post">
用户1id :<input type="text" name="userMap['1'].id"><br>
用户1名: <input type="text" name="userMap['1'].name"><br>
1地址: <input type="text" name="userMap['1'].address.value"><br> <%--级联属性--%>
用户2id :<input type="text" name="userMap['2'].id"><br>
用户2名: <input type="text" name="userMap['2'].name"><br>
2地址: <input type="text" name="userMap['2'].address.value"><br> <%--级联属性--%>
<input type="submit" value="注册">
</form>
测试地址
:http://localhost:8080/Map.jsp
【JSON数据】
- 引入jquery静态文件,需要注意,js文件不需要被DispatcherServlet处理,因此在web.xml中配置静态文件过滤。
<!--静态js文件不被DispatcherServlet拦截处理-->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
- 通过Ajax异步向后台传递JSON数据,前端代码:
<!--json.jsp页面-->
<script type="text/javascript">
$(function () {
var User = {
"id": 1,
"name": "寒风"
}
$.ajax({
url: "/json",
data: JSON.stringify(User),
type: "POST",
contentType: "application/json;charset=UTF-8",
dataType: "JSON",
success: function (data) {
alert(data.id + "____" + data.name);
}
})
})
</script>
-
后端业务方法
还需要考虑到前端JSON数据传来需要阿里工具包fastjson在后端转换为JavaBean!
- pom.xml导入fastjson依赖
<!--前端JSON数据转换成JavaBean--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency>
- spring_mvc.xml进行配置fastjson
<!--springMVC配置fastjson--> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <bean id="fastJsonHttpMessageConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"> <!-- 加入支持的媒体类型:返回contentType--> <property name="supportedMediaTypes"> <list> <!-- 这里顺序不能反,一定先写text/html,不然ie下会出现下载提示 --> <value>text/html;charset=UTF-8</value> <value>application/json;charset=UTF-8</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
@RequestMapping(value = "/json", method = RequestMethod.POST)
@ResponseBody
public User submitJson(@RequestBody User user) { //@RequestBody 接收前端Json数据
System.out.println(user);
user.setId(56);
user.setName("小红");
return user;
}
测试地址
:http://localhost:8080/json.jsp
可能出现两个问题
-
springMVC版本太高不兼容,这里推荐
<version>5.2.6.RELEASE</version>
-
fastjson的jar包为打进war包,需要手动导入。
自定义数据转换器
数据转换器
是指将客户端 HTTP 请求中的参数转换为业务方法中定义的形参,自定义表示开发者可以自主设计转换的方式,HandlerApdter 已经提供了通用的转换,String 转 int,String 转 double,表单数据的封装等,但是在特殊的业务场景下,HandlerAdapter 无法进行转换,就需要开发者自定义转换器。
概括:前端请求参数 ( 映射–>) 业务方法中的形参 ,参数的数据类型也可能需要转换。
举例
Date类型与String类型的转换
- 创建 DateConverter 转换器,实现 Conveter 接口。
public class DateConverter implements Converter<String, Date> {
private String pattern;
public DateConverter(String pattern){
this.pattern = pattern;
}
@Override
public Date convert(String s) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(this.pattern);
Date date = null;
try {
date = simpleDateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
- springmvc.xml 配置转换器。
<!-- 配置自定义转换器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.Long.Converter.DateConverter">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd"></constructor-arg>
</bean>
</list>
</property>
</bean>
<mvc:annotation-driven conversion-service="conversionService">
<mvc:message-converters register-defaults="true">
<!--配置消息转换器,解决后台响应数据时中文乱码-->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/html;charset=UTF-8"/>
</bean>
<!--springMVC配置fastjson-->
<bean id="fastJsonHttpMessageConverter"
class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<!-- 加入支持的媒体类型:返回contentType-->
<property name="supportedMediaTypes">
<list>
<!-- 这里顺序不能反,一定先写text/html,不然ie下会出现下载提示 -->
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
- JSP表单页面
<form action="/converter/date" method="post">
请输入日期:<input type="text" name="date"/>(yyyy-MM-dd)<br/>
<input type="submit" value="提交"/>
</form>
- Handler(业务方法)
@RestController
@RequestMapping("/converter")
public class ConverterHandler {
@RequestMapping("/date")
public String date(Date date){
return date.toString();
}
}
测试地址
http://localhost:8080/date.jsp
模型数据解析
JSP 四大作用域对应的内置对象:
pageContext
、request
、session
、application
。模型数据的绑定是由 ViewResolver 来完成的,实际开发中,我们需要先添加模型数据(model),再交给 ViewResolver 来绑定(View)。
Spring MVC 提供了以下几种方式添加模型数据:
- 【Map】
- 【Model】
- 【ModelAndView】
- 【@SessionAttribute】
- 【@ModelAttribute】
绑定到request 对象
JSP页面
<%--view.jsp页面--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %> <%--不忽略el表达式--%>
<html>
<head>
<title>Title</title>
</head>
<body>
${requestScope.user}
</body>
</html>
1、Map
//通过map将数据传到request域对象里面
@RequestMapping("/map")
public String map(Map<String,User> map){
User user = new User();
user.setId(1);
user.setName("寒风");
map.put("user",user);
return "view";
}
测试地址
http://localhost:8080/map
// User(id=1, name=寒风, address=null)
2、Model
//通过model将数据传到request域对象里面
@RequestMapping("/model")
public String model(Model model){
User user = new User();
user.setId(1);
user.setName("寒风");
model.addAttribute("user",user);
return "view";
}
测试地址
http://localhost:8080/model
// User(id=1, name=寒风, address=null)
3、ModelAndView
//通过ModelAndView将数据传到request域对象里面
@RequestMapping("/modelAndView")
public ModelAndView modelAndView(){
User user = new User();
user.setId(1);
user.setName("寒风");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("user",user);
modelAndView.setViewName("view");
return modelAndView;
}
@RequestMapping("/modelAndView2")
public ModelAndView modelAndView2(){
User user = new User();
user.setId(1);
user.setName("寒风");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("user",user);
View view = new InternalResourceView("/view.jsp");
modelAndView.setView(view);
return modelAndView;
}
@RequestMapping("/modelAndView3")
public ModelAndView modelAndView3(){
User user = new User();
user.setId(1);
user.setName("寒风");
ModelAndView modelAndView = new ModelAndView("view");
modelAndView.addObject("user",user);
return modelAndView;
}
@RequestMapping("/modelAndView4")
public ModelAndView modelAndView4(){
User user = new User();
user.setId(1);
user.setName("寒风");
View view = new InternalResourceView("/view.jsp");
ModelAndView modelAndView = new ModelAndView(view);
modelAndView.addObject("user",user);
return modelAndView;
}
@RequestMapping("/modelAndView5")
public ModelAndView modelAndView5(){
User user = new User();
user.setId(1);
user.setName("寒风");
Map<String,User> map = new HashMap<>();
map.put("user",user);
ModelAndView modelAndView = new ModelAndView("view",map);
return modelAndView;
}
@RequestMapping("/modelAndView6")
public ModelAndView modelAndView6(){
User user = new User();
user.setId(1);
user.setName("寒风");
Map<String,User> map = new HashMap<String,User>();
map.put("user",user);
View view = new InternalResourceView("/view.jsp");
ModelAndView modelAndView = new ModelAndView(view,map);
return modelAndView;
}
@RequestMapping("/modelAndView7")
public ModelAndView modelAndView7(){
User user = new User();
user.setId(1);
user.setName("寒风");
ModelAndView modelAndView = new ModelAndView("view","user",user);
return modelAndView;
}
@RequestMapping("/modelAndView8")
public ModelAndView modelAndView8(){
User user = new User();
user.setId(1);
user.setName("寒风");
View view = new InternalResourceView("/view.jsp");
ModelAndView modelAndView = new ModelAndView(view,"user",user);
return modelAndView;
}
测试地址
http://localhost:8080/modelAndView
4、HttpServletRequest
@RequestMapping("/request")
public String request(HttpServletRequest request){
User user = new User();
user.setId(1);
user.setName("寒风");
request.setAttribute("user",user);
return "view";
}
5、@ModelAttribute
- 定义一个方法,该方法专门用来返回要填充到模型数据中的对象。
@ModelAttribute
public User getUser(){
User user = new User();
user.setId(1);
user.setName("寒风");
return user;
}
@ModelAttribute
public void getUser(Map<String,User> map){
User user = new User();
user.setId(1);
user.setName("寒风");
map.put("user",user);
}
@ModelAttribute
public void getUser(Model model){
User user = new User();
user.setId(1);
user.setName("寒风");
model.addAttribute("user",user);
}
- 业务方法中无需再处理模型数据,只需返回视图即可。
@RequestMapping("/modelAttribute")
public String modelAttribute(){
return "view";
}
绑定到 session 对象
1、原生的 Servlet API
@RequestMapping("/session")
public String session(HttpServletRequest request){
HttpSession session = request.getSession();
User user = new User();
user.setId(1);
user.setName("寒风");
session.setAttribute("user",user);
return "view";
}
@RequestMapping("/session2")
public String session2(HttpSession session){
User user = new User();
user.setId(1);
user.setName("寒风");
session.setAttribute("user",user);
return "view";
}
2、@SessionAttribute
@SessionAttributes(value = {"user","address"})
public class ViewHandler {
}
对于 ViewHandler 中的所有业务方法,只要向 request 中添加了 key = “user”、key = “address” 的对象时,Spring MVC 会自动将该数据添加到 session 中,保存 key 不变。
@SessionAttributes(types = {User.class,Address.class})
public class ViewHandler {
}
对于 ViewHandler 中的所有业务方法,只要向 request 中添加了数据类型是 User 、Address 的对象时,Spring MVC 会自动将该数据添加到 session 中,保存 key 不变。
绑定到 application 对象
@RequestMapping("/application")
public String application(HttpServletRequest request){
ServletContext application = request.getServletContext();
User user = new User();
user.setId(1);
user.setName("寒风");
application.setAttribute("user",user);
return "view";
}
REST
REST:Representational State Transfer,资源表现层状态转换,是目前比较主流的一种互联网软件架构,它结构清晰、标准规范、易于理解、便于扩展。
- 资源(Resource)
网络上的一个实体,或者说网络中存在的一个具体信息,一段文本、一张图片、一首歌曲、一段视频等等,总之就是一个具体的存在。可以用一个 URI(统一资源定位符)指向它,每个资源都有对应的一个特定的 URI,要获取该资源时,只需要访问对应的 URI 即可。
- 表现层(Representation)
资源具体呈现出来的形式,比如文本可以用 txt 格式表示,也可以用 HTML、XML、JSON等格式来表示。
- 状态转换(State Transfer)
客户端如果希望操作服务器中的某个资源,就需要通过某种方式让服务端发生状态转换,而这种转换是建立在表现层之上的,所以叫做"表现层状态转换"。
特点
- URL 更加简洁。
- 有利于不同系统之间的资源共享,只需要遵守一定的规范,不需要进行其他配置即可实现资源共享。
如何使用
REST 具体操作就是 HTTP 协议中四个表示操作方式的动词分别对应 CRUD 基本操作。
GET 用来表示获取资源。
POST 用来表示新建资源。
PUT 用来表示修改资源。
DELETE 用来表示删除资源。
Handler业务方法(增删改查)
@RestController
@RequestMapping("/rest")
public class RestfulHandler {
@Autowired
private StudentRepository studentRepository;
//查 发送get请求
@GetMapping("/findAll")
public Collection<Student> findAll(HttpServletResponse response){
response.setContentType("text/json;charset=UTF-8");
return studentRepository.findAll();
}
@GetMapping("/findById/{id}")
public Student findById(@PathVariable("id") Integer id){
return studentRepository.findById(id);
}
//增 发送post请求
@PostMapping("/save")
public void save(@RequestBody Student student){
studentRepository.saveOrUpdate(student);
}
//改 发送put请求
@PutMapping("/update")
public void update(@RequestBody Student student){
studentRepository.saveOrUpdate(student);
}
//删 发送delete请求
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") Integer id){
studentRepository.deleteById(id);
}
}
模拟Service层接口
public interface StudentRepository {
Collection<Student> findAll();
Student findById(Integer id);
void saveOrUpdate(Student student);
void deleteById(Integer id);
}
Service层实现类+模拟数据库(Dao层)
@Repository //交给IOC容器
public class StudentRepositoryImpl implements StudentRepository {
private static Map<Integer, Student> studentMap;
static {
studentMap = new HashMap<Integer, Student>();
studentMap.put(1, new Student(1, "小寒", 22));
studentMap.put(2, new Student(2, "小肖", 18));
studentMap.put(3, new Student(3, "小乐", 18));
}
@Override
public Collection<Student> findAll() {
return studentMap.values();
}
@Override
public Student findById(Integer id) {
return studentMap.get(id);
}
@Override
public void saveOrUpdate(Student student) {
studentMap.put(student.getId(), student);
}
@Override
public void deleteById(Integer id) {
studentMap.remove(id);
}
}
实体类Student
@Data
@AllArgsConstructor
public class Student {
private Integer id;
private String name;
private Integer age;
}
测试地址:
http://localhost:8080/rest/findAll (查) 注:增删改用Postman
文件上传下载
单文件上传
底层是使用
Apache fileupload 组件
完成上传,Spring MVC 对这种方式进行了封装。
- pom.xml导入commons-io和commons-fileupload的jar包
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
- upload.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/file/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit" value="上传"/>
</form>
<img src="${path}">
</body>
</html>
1、input 的 type 设置为 file。
2、form 的 method 设置为 post(get 请求只能将文件名传给服务器)
3、from 的 enctype 设置为 multipart-form-data(如果不设置只能将文件名传给服务器)
- Handler业务方法
@Controller
@RequestMapping("/file")
public class FileHandler {
@PostMapping("/upload")
public String upload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) {
if (file.getSize() > 0) {
//获取保存上传文件的file路径
String path = request.getServletContext().getRealPath("/upload");
File realpath = new File(path);
//获取上传的文件名
String name = file.getOriginalFilename();
//保存上传之后的文件路径
System.out.println("上传文件保存地址为:" + realpath);
if (!realpath.exists())
realpath.mkdir();
try {
file.transferTo(new File(realpath + "/" + name));
request.setAttribute("path","/upload/" + name);
} catch (IOException e) {
e.printStackTrace();
}
}
return "upload";
}
}
- spring_mvc.xml配置上传组件
<!-- 配置上传组件 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
- web.xml 配置静态文件(.png和.jpg)过滤,否则客户端无法访问 png和jpg文件
<!--静态png和jpg图片文件不被DispatcherServlet拦截处理-->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
多文件上传
- pom.xml还需额外导入jstl和taglibs的jar包
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
- uploads.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/file/uploads" method="post" enctype="multipart/form-data">
file1:<input type="file" name="files"/><br/>
file2:<input type="file" name="files"/><br/>
file3:<input type="file" name="files"><br/>
<input type="submit" value="上传"/>
</form>
<c:forEach items="${Files}" var="file">
<img src="${file}" width="300px">
</c:forEach>
</body>
</html>
- Handler业务方法
@PostMapping("/uploads")
public String uploads(@RequestParam("files") CommonsMultipartFile[] files,HttpServletRequest request){
List<String> fileList = new ArrayList<String>();
for (MultipartFile file:files){
if(file.getSize()>0){
//获取保存上传文件的file路径
String path = request.getServletContext().getRealPath("/upload");
//获取上传的文件名
String name = file.getOriginalFilename();
File realpath = new File(path);
//如果不存在upload文件夹,就自动创建
if (!realpath.exists())
realpath.mkdir();
try {
file.transferTo(new File(realpath + "/" + name));
//保存上传之后的文件路径
fileList.add("/upload/"+name);
} catch (IOException e) {
e.printStackTrace();
}
}
}
request.setAttribute("Files",fileList);
return "uploads";
}
文件下载
- Handler业务方法
@GetMapping("/download/{name}")
public void download(@PathVariable("name") String name, HttpServletRequest request, HttpServletResponse response){
if(name != null){
name += ".png";
String path = request.getServletContext().getRealPath("/upload");
File file = new File(path,name);
OutputStream outputStream = null;
if(file.exists()){
response.setContentType("application/forc-download");
response.setHeader("Content-Disposition","attachment;filename="+name);
try {
outputStream = response.getOutputStream();
outputStream.write(FileUtils.readFileToByteArray(file));
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
- download.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="/file/download/1">1.png</a>
<a href="/file/download/2">2.png</a>
<a href="/file/download/3">3.png</a>
</body>
</html>
后端数据校验
Annotation JSR - 303 标准
使用 Annotation JSR - 303 标准进行验证,需要导入支持这种标准的依赖 jar 文件,这里我们使用 Hibernate Validator。
- 创建实体Person类
@Data
public class Person {
@NotEmpty(message = "用户名不能为空")
private String username;
@Size(min = 6, max = 12, message = "密码6-12位")
private String password;
@Email(message = "请输入正确的邮箱格式")
private String email;
@Pattern(regexp = "^(13[0-9]|14[01456879]|15[0-3,5-9]|16[2567]|17[0-8]|18[0-9]|19[0-3,5-9])\\d{8}$", message = "请输入正确的电话")
private String phone;
}
- 业务方法
@Controller
public class validationHandler {
@GetMapping("/validator")
public String register(Model model){
model.addAttribute("person",new Person());
return "validator";
}
@PostMapping("/validator")
public String register(@Valid Person person, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "validator";
}
return "index";
}
}
- validator.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form:form modelAttribute="person" action="/validator" method="post">
用户名:<form:input path="username"></form:input><form:errors path="username"/><br/>
密码:<form:password path="password"></form:password><form:errors path="password"/><br/>
邮箱:<form:input path="email"></form:input><form:errors path="email"/><br/>
电话:<form:input path="phone"></form:input><form:errors path="phone"/><br/>
<input type="submit" value="提交"/>
</form:form>
</body>
</html>
- 测试页面