Java框架--Spring MVC
作者:互联网
Spring MVC
执行流程
@RequestMapping
value
-
可以指定控制器/处理器的某个方法的请求的url
-
可以修饰方法,还可以修饰类 当同时修饰类和方法时,请求的url就是组合 /类请求值/方法请求值
-
Ant风格资源地址
- ?:匹配文件名中的一个字符(/user/createUser??:匹配/user/createUseraa、/user/createUserbb等URL)
- * :匹配文件名中的任意字符(/user/*/createUser:匹配/user/aaa/createUser、/user/bbb/createUser等URL)
- ** :匹配多层路径(/user/**/createUser:匹配/user/createUser、/user/aaa/bbb/createUser等URL)
-
配合@PathVariable 映射URL绑定占位符
//@RequestMapping(value = "/reg/{name}/{age}") 这里的name、age叫路径变量 //@PathVariable("name") String username 这里意思是把路径变量放入方法形参 @RequestMapping(value = "/reg/{name}/{age}") public String register(@PathVariable("name") String username,@PathVariable("age")String userid)
method
- 使用 RequestMethod 枚举值
- 常用枚举:POST、GET、DELECT、PUT
params
- params = "bookId" 标识请求目标方法时,必须给一个bookId参数,值没有限制
- params = "bookId=101" 标识请求目标方法时,必须给一个bookId参数,值必须为101
注意事项
-
映射的url不能重复
-
请求简写
-
@RequestMapping(value = "/buy",method = RequestMethod.POST) 等 价 @PostMapping(value = "/buy")
-
简写一览: @GetMapping @PostMapping @PutMapping @DeleteMapping
-
-
RequestMapping标识的方法如果提供了形参名,会从请求的参数中去匹配同名参数(没找到会设置为null,根据HttpRequest.getParameter方法返回值)
Rset(优雅的url请求风格)
Representational State Transfer。(资源)表现层状态转化。是目前流行的请求方式。它结构清晰,很多网站采用
HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。(传统通过参数来说明crud类型,rest是通过请求类型来说明crud类型)
REST的核心过滤器
-
当前的浏览器form表单只支持GET与POST请求,而DELETE、PUT等method并不支持,Spring添加了一个过滤器,可以将这些请求转换为标准的http方法,使得支持GET、POST、PUT与DELETE请求
-
HiddenHttpMethodFilter能对post请求方式进行转换,原理就是对post请求中的隐藏字段_method进行判断,将此请求转换为目标类型的请求,也就是说,只有post会进行转换,转换的目标是:post、put、delete..请求
-
此过滤器在web.xml中配置,进行全部请求的过滤转换,同时也配置容器xml文件开启Mvc高级功能
web.xml <!--配置HiddenHttpMethodFilter过滤器 将以post方式提交的delete、put等请求进行请求类型转换 --> <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> 会匹配到/login这样的路径型url,不会匹配到模式为*.jsp这样的后缀型url。 <url-pattern>/*</url-pattern> 会匹配所有url:路径型的和后缀型的url(包括/login,.jsp,.js和*.html等)。 <url-pattern>/</url-pattern> 不会匹配到*.jsp,即:*.jsp不会进入springmvc的 DispatcherServlet类 。 <url-pattern>/*</url-pattern> 会匹配*.jsp,会出现返回jsp视图时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。 --> <url-pattern>/*</url-pattern> </filter-mapping> 容器xml <!--配置两个常规配置(使用HiddenHttpMethodFilter过滤器时配置)--> <!--支持springmvc的高级功能,比如JSR303效验,映射动态请求 注意选择引入xmlns:mvc="http://www.springframework.org/schema/mvc"--> <mvc:annotation-driven/> <!--将springmvc不能处理的请求交给tomcat处理,比如css\js请求--> <mvc:default-servlet-handler/>
应用
/**
* 处理rest风格的请求,包括crud
*/
@RequestMapping("/user")
@Controller
public class BookHandler {
@RequestMapping(value = "/book/{bookId}", method = RequestMethod.GET)
public String getBook(@PathVariable("bookId") String bookId){
System.out.println("查询书籍Id = " + bookId);
return "success";
}
@RequestMapping(value = "/book", method = RequestMethod.POST)
public String addBook(String bookName){
System.out.println("添加书籍 = " + bookName);
return "success";
}
@RequestMapping(value = "/book/{bookId}", method = RequestMethod.DELETE)
public String delBook(@PathVariable("bookId") String bookId){
System.out.println("delBook ID = " + bookId);
//return "success"; //HTTP Status 405 - JSPs only permit GET POST or HEAD 由于jsp页面仅支持post、get请求
return "redirect:/user/success"; //重定向自动转为get,临时使用,后续使用前端框架vue不存在此问题
}
@RequestMapping(value = "/book/{bookId}", method = RequestMethod.PUT)
public String UpdBook(@PathVariable("bookId") String bookId){
System.out.println("UpdBook ID = " + bookId);
//return "success"; //HTTP Status 405 - JSPs only permit GET POST or HEAD 由于jsp页面仅支持post、get请求
return "redirect:/user/success"; //重定向自动转为get,临时使用,后续使用前端框架vue不存在此问题
}
@RequestMapping(value = "/success")
public String successGenecal(){
return "success";
}
}
映射请求数据
获取参数
开发中,会遇到请求的参数和实际方法形参名称不一致,这时候可以使用@RequestParam来映射请求中真正的参数,就类似于重新链接请求参数和实际方法形参(前面提到RequestMapping标识的方法如果提供了形参名,会从请求的参数中去匹配同名参数,不一致则置空,这里就可以重新关联)
/**
* 当形参和实际请求中的参数名不一致时,使用RequestParam(形参username,实际请求参数name)
* required = true,请求中就必须提供name参数,否则报错(反之不会报错,继续置空)
* @param username 用户名
* @return 视图解析
*/
@RequestMapping("/vote01")
public String test01(@RequestParam(value = "name", required = false) String username){
System.out.println("得到username = " + username);
return "success";
}
获取http请求头
/**
* 获取请求头参数
* @return 视图解析
*/
@RequestMapping("/vote02")
public String test02(@RequestHeader("Accept-Encoding") String ae,
@RequestHeader("HOST") String host){
System.out.println("Accept-Encoding: " + ae);
System.out.println("HOST: " + host);
return "success";
}
获取javaBean形式的数据
开发中,客户提交表单本身就是一个javabean数据,springmvc支持直接将请求参数封装为一个javabean对象
/**
* 获取javaBean对象
* 直接在方法的形参上用对应的javaBean类型即可自动封装
* 注意1:自动封装会根据javaBean类型的属性字段名到请求参数中去找一致的值,不一致为null
* 注意2:如果属性是对象,请求的参数名为pet.id、pet.name,进行级联封装
* @return 视图解析
*/
@RequestMapping("/vote03")
public String test03(Master master){
System.out.println("master = " + master);
return "success";
}
//测试链接: http://localhost:8080/springmvc/vote/vote03?id=1&name=szl&pet.id=2&pet.name=xh
获取原生servlet api
开发中,如果需要获取原生的servlet-api使用,需要先引入tomcat/lib下的servlet-api.jar,然后直接使用方法形参来获取
/**
* 获取servlet api, 来获取提交的数据
* @return 视图解析
*/
@RequestMapping("/vote04")
public String test04(HttpServletRequest request, HttpServletResponse response){
String name = request.getParameter("name");
System.out.println("name = " + name);
return "success";
}
-
除了 HttpServletRequest, HttpServletResponse 还有其他api对象可以获取:HttpSession、java.security.Principal,InputStream,OutputStream,Reader,Writer ......
-
其中一些对象也可以通过 HttpServletRequest / HttpServletResponse 对象获取,比如 Session 对象 ,既可以通过参数传入,也以通过 request.getSession() 获取,效果一样,推荐使用参数形式传入,更加简单明了
模型数据(域数据)
实际应用中,我们常常会用到数据传递,这时候就会用到模型数据的传递(域数据方式-可以回顾servlet基础),因为实际数据来源的地方可能是前端或者数据库
模型数据/域数据最简单的理解就是类似全局映射的map,web相关的代码片段都可以访问此map
数据放入request
开发中,控制器/处理器中获取的数据如何放入request域,然后在前端(VUE/JSP/...)取出显示
-
默认机制
/** * 将提交的数据封装到java对象时,springmvc 同时会把此对象自动放入到request域,名字就是此对象类型的首字母小写 * 比如:Master类型对象就是master,此方法调用后,request域中已存在key为master的Master类型封装对象 * 注意:如果在方法中修改了Master类型对象的值,那么也会影响request域中的类型对象值 * @return 视图解析 */ @RequestMapping("/vote05") public String test05(Master m){ m.setName("aa"); return "vote_ok"; }
-
使用servlet-api
/** * 使用HttpServletRequest 对象设置属性 * @return 视图解析 */ @RequestMapping("/vote05") public String test05(HttpServletRequest request){ request.setAttribute("address", "beijing"); return "vote_ok"; }
-
通过Map<String,Object>
/** * 通过Map<String,Object> 设置数据到request域 * 原理:数据渲染的时候springmvc会将方法执行完成后的map中的key、value遍历放入到request域中 * 注意:如果使用 map.put("master", null),会将原本springmvc自动放入request域中的master指向修改 * @return 视图解析 */ @RequestMapping("/vote06") public String test06(Master m, Map<String,Object> map){ map.put("address", "shanghai..."); //map.put("master", null); return "vote_ok"; }
-
通过ModelAndView
/** * 通过ModelAndView设置数据到request域 * @return 视图解析 */ @RequestMapping("/vote07") public ModelAndView test07(Master m){ ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("address", "fuzhou..."); //这里如果执行一下语句,和使用map一样,会将原本springmvc自动放入request域中的master指向修改 //modelAndView.addObject("master", null); //这里我们把原本让springmvc自动封装的动作,自己实现了,然后返回ModelAndView类型对象 modelAndView.setViewName("vote_ok"); return modelAndView; }
数据放入Session域
/**
* 把模型数据放入Session域
* @return 视图解析
*/
@RequestMapping("/vote08")
public String test08(Master m, HttpSession httpSession){
httpSession.setAttribute("address", "guangzhou...");
httpSession.setAttribute("master", m);
return "vote_ok";
}
@ModelAttribute
开发中,有时需要使用某个前置方法(比如prepareXxx(),方法名由程序员定)给目标方法准备一个模型对象,@ModelAttribute注解标注一个方法之后,那么调用该Handler的任何一个方法时,都会先调用这个方法
/**
* ModelAttribute 标识后,此方法就变为前置方法
* 它的作用域在本类所有方法前生效
*/
@ModelAttribute
public void prepareModel(){
System.out.println("prepareModel() -----完成准备工作------");
}
最佳实践:预先查询数据库准备数据,进行下一步处理
视图和视图解析器
在springmvc中的目标方法最终返回都是一个视图(有各种视图),返回的视图都会由一个视图解析器来处理(视图解析器有很多种)
自定义视图解析器:在默认情况下,我们都是返回默认的视图,然后这个返回的视图交由SpringMVC的InternalResourceViewResolver视图处理器来处理的;在实际开发中,我们有时需要自定义视图,这样可以满足更多更复杂的需求
视图解析器:原理是循环来执行每个视图解析器,根据配置的order值越小的先执行,如果执行成功返回,既结束后续的视图渲染,失败则继续执行下一视图(当配置了BeanNameViewResolver、InternalResourceViewResolver,根据优先级order值来for循环执行)
自定义视图
-
配置容器XML启动自定义视图配置,同时设置其执行优先级,确保在InternalResourceViewResolver视图前被调用
<!--配置自定义视图解析器--> <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"> <!--这里设置执行顺序,默认顺序是Integer.MAX_VALUE,最低(InternalResourceViewResolver就是默认最低)--> <property name="order" value="99"/> </bean>
-
创建继承AbstractView的类,同时实现renderMergedOutputModel 方法 放入容器@Component(value = "szlView")起个beanId
@Component(value = "szlView") public class MyView extends AbstractView { @Override protected void renderMergedOutputModel(Map<String, Object> map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { System.out.println("进入自己的视图"); //下面就是进行请求转发到/WEB-INF/pages/my_view.jsp httpServletRequest.getRequestDispatcher("/WEB-INF/pages/my_view.jsp") .forward(httpServletRequest, httpServletResponse); } }
-
使用字符串指定视图名,因BeanNameViewResolver会先执行,"szlView"会匹配到@Component(value = "szlView") 的bean视图类
@RequestMapping("/goods") @Controller public class GoodsHandler { @RequestMapping("/buy") public String buy(){ System.out.println("------buy-------"); return "szlView"; } }
目标方法指定转发或重定向
@RequestMapping("/goods")
@Controller
public class GoodsHandler {
/**
* 演示直接指定要请求转发的或者是重定向的页面
* @return
*/
@RequestMapping(value = "/order")
public String order() {
System.out.println("=======order()=====");
//请求转发到 /WEB-INF/pages/my_view.jsp
//下面的 /WEB-INF/pages/my_view.jsp 被解析成 /springmvc/WEB-INF/pages/my_view.jsp
//return "forward:/WEB-INF/pages/my_view.jsp";
//return "forward:/aaa/bbb/ok.jsp";
//直接指定要重定向的页面
//1. 对于重定向来说,不能重定向到 /WEB-INF/ 目录下
//2. redirect 关键字,表示进行重定向
//3. /login.jsp 在服务器解析 /springmvc/login.jsp
return "redirect:/login.jsp";
// /WEB-INF/pages/my_view.jsp 被解析 /springmvc/WEB-INF/pages/my_view.jsp
//return "redirect:/WEB-INF/pages/my_view.jsp";
}
}
视图类型有很多种:redirect重定向 - RedirectView 、 forward转发 - InternalResourceView ......
它们都实现View接口,只要实现了就代表此类是视图,自定义视图就是实现了View接口,配置好自定义视图解析器即可同步加入使用
标签:return,String,--,Spring,视图,MVC,请求,public,RequestMapping 来源: https://www.cnblogs.com/shaozelong/p/16441305.html