参考
官方文档:https://docs.spring.io/spring-framework/docs/5.3.5-SNAPSHOT/reference/html/web.html#spring-web
其他:https://blog.csdn.net/litianxiang_kaola/article/details/79169148
【狂神说Java】SpringMVC最新教程IDEA版通俗易懂
配置
继承 Controller方式
注解方式
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?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>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
<servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
|
spring-servlet.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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="com.wnh.controller"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <property name="prefix" value="/WEB-INF/module/"/> <property name="suffix" value=".jsp"/> </bean>
</beans>
|
测试
1 2 3 4 5 6 7 8 9
| @Controller public class HelloController{
@RequestMapping("/hello") public String hello(Model model){ model.addAttribute("msg","helloSpringMVC"); return "test"; } }
|
乱码问题
web.xml
1 2 3 4 5 6 7 8 9 10 11 12
| <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-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>
|
@RequestMapping
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
RequestMapping注解有六个属性,下面我们把这些属性分成三类进行说明。
1、value属性、method属性
value:指定请求的实际地址,指定的地址可以是URI Template模式
method:指定请求的method类型,例如GET、POST、PUT、DELETE等;
2、consumes属性、produces属性
consumes:指定处理请求的提交内容类型(Content-Type),例如application/json、text/html等
produces:指定返回的内容类型,仅当Request请求头中的(Accept)类型中包含该指定类型才返回
3、params属性、headers属性
params:指定request中必须包含某些参数值是,才让该方法处理
headers:指定request中必须包含某些指定的header值,才能让该方法处理请求
RestFul风格
1 2 3 4 5 6 7 8 9 10
| @RequestMapping("/add") public String add(int a,int b,Model model){ model.addAttribute("msg",a+b+"的结果为"+(a+b)); return "test"; } @RequestMapping("/add/{a}/{b}") public String add0(@PathVariable int a,@PathVariable int b, Model model){ model.addAttribute("msg","结果为"+(a+b)); return "test"; }
|
原本url:http://localhost:8080/springmvc/add?a=1&b=2
RestFul:http://localhost:8080/springmvc/add/3/4
@RequestParam
接受前端传递的参数,只有符合@RequestParam()配置才接收,若是对象可直接传入
1 2 3 4 5
| @RequestMapping("/t1") public String test1(@RequestParam("username") String name) { System.out.println(name); return "test"; }
|
转发与重定向
配置视图解析器默认转发
- forward: //请求转发
- redirect: //重定向
重定向
1 2 3 4
| @RequestMapping("redirect") public String redirect(){ return "redirect:must.jsp"; }
|
AJAX 与 JSON
jackson
导包
1 2 3 4 5
| <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.10.0</version> </dependency>
|
实体类对象
Controller
1 2 3 4 5 6 7 8 9 10 11 12
| ```java @RequestMapping(value = "j1",produces = "text/json;charset=UTF-8") @ResponseBody public String json1() throws JsonProcessingException { // jackson ObjectMapper ObjectMapper mapper=new ObjectMapper();
User user=new User(1,"小王","dbfd");
return mapper.writeValueAsString(user); }
|
SpringMVC 配置解决
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <constructor-arg value="UTF-8"/> </bean> <bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> <property name="failOnEmptyBeans" value="false"/> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
|
结果
{"id":1,"name":"小王","pwd":"dbfd"}
简单集合
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @RequestMapping(value = "j1") @ResponseBody public String json1() throws JsonProcessingException { ObjectMapper mapper=new ObjectMapper(); List<User> userList=new ArrayList<>();
User user1=new User(1,"小王","dbfd"); User user2=new User(2,"大王","55vgh"); User user3=new User(3,"老王","d785d"); User user4=new User(4,"少王","86fd");
userList.add(user1); userList.add(user2); userList.add(user3); userList.add(user4);
return mapper.writeValueAsString(userList); }
|
结果
[{"id":1,"name":"小王","pwd":"dbfd"},{"id":2,"name":"大王","pwd":"55vgh"},{"id":3,"name":"老王","pwd":"d785d"},{"id":4,"name":"少王","pwd":"86fd"}]
时间对象
Controller
1 2 3 4 5 6 7
| @RequestMapping(value = "j2") @ResponseBody public String json2() throws JsonProcessingException { Date data=new Date(); return new ObjectMapper().writeValueAsString(data); }
|
结果
1613656289365
ObjectMapper 时间解析默认格式为:Timetamp:时间戳
格式化
1 2 3 4 5 6 7 8 9
| @RequestMapping(value = "j2") @ResponseBody public String json2() throws JsonProcessingException { Date data=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return new ObjectMapper().writeValueAsString(sdf.format(data)); }
|
结果
"2021-02-18 21:55:51"
ObjectMapper 解决
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false)
关闭默认时间戳方式
.setDateFormat(sdf) 自定义时间格式
1 2 3 4 5 6 7 8 9 10 11
| @RequestMapping(value = "j2") @ResponseBody public String json2() throws JsonProcessingException { Date data=new Date();
// SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // // return new ObjectMapper().writeValueAsString(sdf.format(data));
return new ObjectMapper().configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false).writeValueAsString(data); }
|
结果
"2021-02-18T14:00:26.890+0000"
JsonUtil
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class JsonUtil { public static String getJson(Object object) { return getJson(object, "yyyy-MM-dd HH:mm:ss"); }
public static String getJson(Object object, String dataFormat) { ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); SimpleDateFormat sdf = new SimpleDateFormat(dataFormat); mapper.setDateFormat(sdf);
try { return mapper.writeValueAsString(object); } catch (JsonProcessingException e) { e.printStackTrace(); } return null; } }
|
fastjson
导包
1 2 3 4 5
| <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.1.41</version> </dependency>
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| @RequestMapping(value = "j4") @ResponseBody public String json4() { List<User> userList = new ArrayList<>();
User user1 = new User(1, "小王", "dbfd"); User user2 = new User(2, "大王", "55vgh"); User user3 = new User(3, "老王", "d785d"); User user4 = new User(4, "少王", "86fd");
userList.add(user1); userList.add(user2); userList.add(user3); userList.add(user4);
System.out.println("*******Java对象 转 JSON字符*******"); String str1 = JSON.toJSONString(userList); System.out.println("JSON.toJS0NString(list)==>" + str1); String str2 = JSON.toJSONString(user1); System.out.println("JSON.toJS0NString(user1)==>" + str2);
System.out.println("\n****** JSON字符串 转 Java对象*******"); User jp_user1 = JSON.parseObject(str2, User.class); System.out.println("JSON. parseObject(str2,User.class)==>" + jp_user1);
System.out.println("\n****** Java对象 转 JSON对象*****"); JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2); System.out.println("(JSONObject) JSON. toJSON(user2)==> " + jsonObject1.getString("name"));
System.out.println("\n****** JSON对象 转 Java对象*****"); User to_java_user = JSON.toJavaObject(jsonObject1, User.class); System.out.println("JSON. toJavaObject(jsonObject1, User.class)==>" + to_java_user); return "Hello"; }
|
结果
1 2 3 4 5 6 7 8 9 10 11 12
| *******Java对象 转 JSON字符******* JSON.toJS0NString(list)==>[{"id":1,"name":"小王","pwd":"dbfd"},{"id":2,"name":"大王","pwd":"55vgh"},{"id":3,"name":"老王","pwd":"d785d"},{"id":4,"name":"少王","pwd":"86fd"}] JSON.toJS0NString(user1)==>{"id":1,"name":"小王","pwd":"dbfd"}
****** JSON字符串 转 Java对象******* JSON. parseObject(str2,User.class)==>User(id=1, name=小王, pwd=dbfd)
****** Java对象 转 JSON对象***** (JSONObject) JSON. toJSON(user2)==> 大王
****** JSON对象 转 Java对象***** JSON. toJavaObject(jsonObject1, User.class)==>User(id=2, name=大王, pwd=55vgh)
|
实例
后端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @RequestMapping(value = "addComment", produces = "text/json;charset=UTF-8") @ResponseBody public String addComment(Comment comment) { int result = frontService.AddComment(comment); Map<String, Object> map = new HashMap<String, Object>(); if (result > 0) { long LastId = comment.getComment_id(); map.put("result", "success"); map.put("cid", LastId); System.out.println("评论成功"); } else { map.put("result", "fail"); System.out.println("评论失败"); } return JSON.toJSONString(map); }
|
前端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| $(function () { var css = { marginLeft: 'auto', marginRight: 'auto', width: '70%', height: 'auto', }; $("#show").css(css); $("#sendTo").click(function () { var uid = '${sessionScope.userS.userId}'; var uname = '${sessionScope.userS.userName}'; var nid = '${news.newsId}'; var content = $("#content").val(); var uIcon = '${sessionScope.userS.userIcon}'; if (content !== "") { $.ajax({ url: "${pageContext.request.contextPath}/addComment", type: "post", data: {user_id: uid, news_id: nid, content: content}, dataType: "json", success: function (data) { if (data.result === 'success') { alert("评论成功"); var iconSrc="${pageContext.request.contextPath}/Static/img/userIcon.png" if("" !== uIcon){ iconSrc=uIcon; } $("#content").val(''); var s = '<div class="layui-card" id="div_' + data.cid + '">' + '<div class="layui-card-body">' + '<div align="left">' + '<a href="${pageContext.request.contextPath}/queryUserById?uid='+uid+'">' + '<img class="layui-nav-img" src="' + iconSrc + '"/>' + uname + '</a>' + ' </div>' + content + '<div align="right">' + '<a href="javascript:void(0);" onclick="delComment(' + data.cid + ')">删除</a>' + '</div>' + '<div align="right">' + getCurrentDate(new Date()) + '</div>' + '</div>' + '</div>'; $("#newComment").prepend(s); } else { alert("评论失败"); } } }) } else { alert("评论不能为空!"); } }); });
|
拦截器
Spring
MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
要使用Spring MVC中的拦截器,就需要对拦截器类进行定义和配置。
通过实现HandlerInterceptor接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class MyInterceptor implements HandlerInterceptor {
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle"); return true; }
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); } }
|
自定义拦截器实现了HandlerInterceptor接口,并实现了接口中的三个方法:
- preHandle()
方法:该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true时,表示继续向下执行;
当其返回值为false时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。
- postHandle()方法:该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。
- afterCompletion()方法:该方法会在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。
配置
1 2 3 4 5 6 7
| <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.wnh.interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>
|
path 的属性值“/**” 表示拦截所有路径,“/hello” 表示拦截所有以 “/hello”
结尾的路径。
注意:中的子元素必须按照上述代码中的配置顺序进行编写,即
,否则文件会报错。
文件上传下载
上传
导包
1 2 3 4 5
| <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>
|
配置
1 2 3 4 5 6 7 8
| <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="utf-8"/> <property name="maxUploadSizePerFile" value="5242880"/> <property name="maxInMemorySize" value="40960"/> </bean>
|
前端
1 2 3 4 5
| <h3>文件上传</h3> <form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post" > <input type="file" name="file" /> <input type="submit" value="上传"> </form>
|
后端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| @RequestMapping("upload") public String upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException { if (file.isEmpty()) { return "failed"; } String fileName = file.getOriginalFilename(); System.out.println("上传文件名:"+fileName);
String path = request.getSession().getServletContext().getRealPath("/upload");
File filePath = new File(path); if (!filePath.exists()){ filePath.mkdirs(); } System.out.println("上传保存地址:"+filePath);
file.transferTo(new File(filePath+"/"+fileName));
return "success"; }
|
下载
前端
1 2
| <h3>文件下载</h3> <a href="${pageContext.request.contextPath}/download">下载</a>
|
后端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @RequestMapping("download") public String download(HttpServletRequest request, HttpServletResponse response) throws IOException { String path = request.getServletContext().getRealPath("/upload"); String fileName="wnhyang.jpg"; response.reset(); response.setCharacterEncoding("UTF-8"); response.setContentType("multipart/form-data"); response.setHeader("Content-Disposition", "attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path,fileName); InputStream in=new FileInputStream(file); OutputStream out = response.getOutputStream();
byte[] bs = new byte[1024]; int len = -1; while(( len = in.read(bs)) !=-1 ) { out.write(bs, 0, len); } out.close(); in.close();
return null; }
|
注意
将之前依赖改了,因为只有 servlet-api 3以上才有
getServletContext()方法
1 2 3 4 5 6 7 8 9 10 11 12
| <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.2.1</version> <scope>provided</scope> </dependency>
|