SpringMVC
也被称为SpringWeb
Spring提供的Web框架,是在Servlet基础上,构建的框架
SpringMVC看成是一个特殊的Servlet,由Spring来编写的Servlet
搭建
- 引入依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.9.RELEASE</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version></dependency>
- web.xlm
<?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><servlet-name>mvcServlet</servlet-name><!--SpringMVC的核心类,请求的入口--><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--读取的配置文件路径--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:mvc1.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>mvcServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!--乱码--></web-app>
- mvc配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--BeanNameUrlHandlerMapping bean对象的名字 url 和 Controller的映射关系--><!--/hello--><!--处理器,映射器--><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/><!--适配器--><bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/><!--视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--跳转的jsp页面,统一添加前缀--><property name="prefix" value="/WEB-INF/"/><!--后缀--><property name="suffix" value=".jsp"/></bean><!--自定义的Controller,需要通过什么路径才能访问到--><bean name="/hello" class="com.javasm.demo.HelloController"/>
</beans>
- 测试Controller
public class HelloController implements Controller {@Overridepublic ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {//ModelAndView 视图 和页面 页面的数据,配置的是跳转到哪个页面,向这个页面传递什么参数ModelAndView mv = new ModelAndView();//跳转的页面 任何情况下,/都表示根路径///WEB-INF/ 是受保护的文件夹,默认在webapp路径下的文件,都可以直接访问,受保护的文件夹,内部文件,不能直接访问//mv.setViewName("/WEB-INF/demo/hello.jsp");mv.setViewName("demo/hello");//携带数据mv.addObject("abc","Hello Web MVC");return mv;}
}
流程
启动流程
启动Tomcat → 加载web.xml文件 → 读取servlet标签的配置 → DispatcherServlet 初始化 → 读取mvc.xml配置文件 → 解析配置文件 → 在Spring容器中实例化Controller → 其他的配置类实例化
访问流程
浏览器发起请求 → Tomcat中 → servlet-mapping 配置了/,所有的请求,都进入DispatcherServlet中 → 能获取到访问路径/hello → 寻找执行的方法 → 找到HelloController,执行方法 → 返回ModelAndView → Model的值放到request作用域,view的值,决定跳转到哪个页面
DispacherServlet内部流程
实际运用的案例
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 开启包扫描--><context:component-scan base-package="com.javasm"/><!--代替适配器等配置--><mvc:annotation-driven/><!--视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--跳转的jsp页面,统一添加前缀--><property name="prefix" value="/WEB-INF/"/><!--后缀--><property name="suffix" value=".jsp"/></bean></beans>
//地址 和 类的映射,通过/demo访问到当前类
@Controller
@RequestMapping("/demo")
public class DemoController {//当前方法的访问路径 /demo/f1@RequestMapping("/f1")public ModelAndView f1(){ModelAndView modelAndView = new ModelAndView();modelAndView.addObject("abc","f1方法");modelAndView.setViewName("demo/hello");return modelAndView;}@RequestMapping("/f2")public ModelAndView f2(){ModelAndView modelAndView = new ModelAndView();modelAndView.addObject("abc","f2方法");//报404,没有这个页面modelAndView.setViewName("demo/f2");return modelAndView;}
}
- 404
找到了Controller,但是没有找到页面
没有找到Controller
乱码配置
<?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><servlet-name>mvcServlet</servlet-name><!--SpringMVC的核心类,请求的入口--><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--读取的配置文件路径--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:mvc2.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>mvcServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!--乱码--><filter><filter-name>luan</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>luan</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>
静态资源文件
<!--静态资源文件放过--><mvc:default-servlet-handler/>
接收参数
- 普通参数
<%--action="/game/doAdd1"http://localhost:8080/game/doAdd1缺少了项目名,/表示根路径,浏览器理解的根路径,是从8080/开始的action="/mvc/game/doAdd1"--%><%--当前页面的路径http://localhost:8080/mvc/game/jumpaction="game/doAdd1"http://localhost:8080/mvc/game/game/doAdd1action="doAdd1"http://localhost:8080/mvc/game/doAdd1--%><%--浏览器,点击刷新按钮,默认是重新提交表单浏览器,url地址栏,选中,按回车,是再次通过get方法,访问这个url地址浏览器url地址栏,只能发送get请求浏览器点击后退的时候,并没有刷新页面,只是读取了电脑本地的缓存--%><hr/><h1>普通参数</h1><form action="doAdd1" method="post"> 对应Controller文件下的@PostMapping("/doAdd1")<p><input type="text" name="gameId" placeholder="请输入游戏ID"/></p><p><input name="gameName" placeholder="请输入游戏名称"></p><p><input type="submit" value="提交"></p></form>
//仅可以使用post方式访问@PostMapping("/doAdd1")public ModelAndView doAdd1(Integer gameId,String gameName){System.out.println(gameId+"----"+gameName);ModelAndView mv = new ModelAndView();mv.setViewName("game/success");//对应在webapp文件下的WEB-INF文件里创建一个game的文件再创建一个success的jsp文件mv.addObject("game",gameName);return mv;}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title></head><body><h1>成功页面</h1><h2>${game}</h2></body></html>
- 数组
<h1>数组参数</h1><form action="/mvc/game/doAdd2" method="post"><p><input type="checkbox" name="hobbys" value="smoke">抽烟</p><p><input type="checkbox" name="hobbys" value="drink">喝酒</p><p><input type="checkbox" name="hobbys" value="run">跑路</p><p><input type="submit" value="提交"></p></form>
@PostMapping("/doAdd2")public ModelAndView doAdd2(String[] hobbys){String hobbysStr = Arrays.toString(hobbys);System.out.println(hobbysStr);ModelAndView mv = new ModelAndView();mv.setViewName("game/success");mv.addObject("game",hobbysStr);return mv;}
- 对象
@PostMapping("/doAdd3")public ModelAndView doAdd3(Game game){System.out.println(game);ModelAndView mv = new ModelAndView();mv.setViewName("game/success");mv.addObject("game",game);return mv;}
- 包装类
//包装类 VO@PostMapping("/doAdd4")public ModelAndView doAdd4(GameVo game){System.out.println(game);ModelAndView mv = new ModelAndView();mv.setViewName("game/success");mv.addObject("game",game);return mv;}
@Data
public class GameVo {private Game game;private Company company;
}
- List和map
<form action="doAdd5" method="post"><p><input type="text" name="playerList[0].lv" placeholder="等级"><input type="text" name="playerList[0].nickname" placeholder="昵称"></p><p><input type="text" name="playerList[1].lv" placeholder="等级"><input type="text" name="playerList[1].nickname" placeholder="昵称"></p><p><input type="text" name="playerList[2].lv" placeholder="等级"><input type="text" name="playerList[2].nickname" placeholder="昵称"></p><p>背包</p><p><input type="text" name="items[1001]"><input type="text" name="items[1002]"><input type="text" name="items[1003]"></p><p><input type="submit" value="提交"></p></form>
@Data
public class GameVo{private Game game;private Company company;List<String> heroList;List<Player> playerList ;Map<Integer,String> items;
}@PostMapping("/doAdd5")public ModelAndView doAdd5(GameVo gameVo){System.out.println(gameVo);ModelAndView mv = new ModelAndView();mv.setViewName("game/success");mv.addObject("game",gameVo);return mv;}
- JSON字符串
引入依赖
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.11.2</version></dependency><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.23</version></dependency>
@PostMapping("/doAdd6")public ModelAndView doAdd6(@RequestBody Game game){System.out.println(game);ModelAndView mv = new ModelAndView();mv.setViewName("game/success");mv.addObject("game",game);return mv;}
@PostMapping("/doAdd7")public ModelAndView doAdd7(@RequestBody List<Player> playerList){System.out.println(playerList);ModelAndView mv = new ModelAndView();mv.setViewName("game/success");mv.addObject("game",playerList);return mv;}@PostMapping("/doAdd8")public ModelAndView doAdd8(@RequestBody GameVo gameVo){System.out.println(gameVo);ModelAndView mv = new ModelAndView();mv.setViewName("game/success");mv.addObject("game",gameVo);return mv;}
{"game":{"gid":1001,"name":"cogo","price":"12.2","type":{"typeName":"fps","typeId":"2000"}},"company":{"id":100,"name":"尚马"},"heroList":["天使","源氏","提莫"],"playerList":[{"lv":10,"nickname":"推车"},{"lv":22,"nickname":"泉水指挥官"}],"items":{"1001":"大宝剑","1002":"激光武器","1003":"核武器"}
}
解决乱码问题
<filter><filter-name>luan</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>luan</filter-name><url-pattern>/*</url-pattern></filter-mapping>
获取ServletAPI
//获取ServletAPI@GetMapping("/test1")public ModelAndView test1(HttpServletRequest request, HttpServletResponse response){HttpSession session = request.getSession();session.setAttribute("user","小明");ModelAndView mv = new ModelAndView();mv.setViewName("game/success");return mv;}@AutowiredHttpServletRequest request;@AutowiredHttpServletResponse response;@AutowiredHttpSession session;@GetMapping("/test2")public ModelAndView test2(){Object user = session.getAttribute("user");System.out.println(user);ModelAndView mv = new ModelAndView();mv.setViewName("game/success");return mv;}
返回值
返回String
跳转的页面地址
//单纯的页面跳转,不想传值@GetMapping("/jump")public String jump(){return "game/player";}
JSON数据
@Controller
@RequestMapping("/player")
public class PlayerController {//单纯的页面跳转,不想传值@GetMapping("/jump")public String jump(){return "game/player";}//只想返回一个字符串,不需要返回页面@ResponseBody@GetMapping("/success")public String success(){return "success";}@GetMapping("/queryById")@ResponseBodypublic Player getById(Integer id){Player player = new Player();player.setLv(id);player.setNickname("昵称-----");return player;}@ResponseBody@GetMapping("/list")public List<Player> list(){return new ArrayList<>();}
}
- 整个类都返回json,没有页面
@RestController
默认,整个类,返回的都是json数据,就不能返回页面了
转发(url地址不变)&重定向(url地址改变)
//测试转发,不能使用json数据返回@GetMapping("/test1")public String test1(){//转发return "forward:test2";}@ResponseBody@GetMapping("/test2")public String test2(){return "我是Test2";}//重定向测试也不能返回json@GetMapping("/test3")public String test3(){//重定向return "redirect:test2";}
ResonseEntity
@ResponseBody@GetMapping("/query/id")public ResponseEntity<Player> query(){Player player = new Player();player.setNickname("不知道");ResponseEntity<Player> entity = new ResponseEntity<>(player, HttpStatus.INTERNAL_SERVER_ERROR);return entity;}
携带Header
@ResponseBody@GetMapping("/query/id2")public ResponseEntity<Player> query2(){Player player = new Player();player.setNickname("不知道");//new header对象HttpHeaders httpHeaders = new HttpHeaders();//header中添加自定义属性httpHeaders.add("javasm","Hello Java ");ResponseEntity<Player> entity = new ResponseEntity<>(player,httpHeaders, HttpStatus.INTERNAL_SERVER_ERROR);return entity;}
简化
@ResponseBody@GetMapping("/query3")public ResponseEntity<String> query3(){//默认状态 200return ResponseEntity.ok("Success!!!!!!!!!!!!!!!");}
@ResponseBody@GetMapping("/query4")public ResponseEntity<String> query4(){return ResponseEntity.status(500).body("Success??????");}
Rest风格
@RestController= @ResponseBody+@Controller
@RestController
@RequestMapping("/company")
public class CompanyController {//不能接收特殊字符,接收简单的参数@GetMapping("/query/{id}/{name}")public Company queryById(@PathVariable("id") Integer cid,@PathVariable String name){Company company = new Company();company.setId(cid);company.setName(name);return company;}@GetMapping(value = {"/query2","/query2/{id}"})public Company query2(@PathVariable(required = false) Integer id){Company company = new Company();company.setId(id);return company;}
}