简介
Spring MVC 属于Spring Framework项目中的一部分。主要用于组建MVC结构的项目。比较相似于Struts的功能。并且Spring MVC对于目前比较流行的RESTful架构风格支持的也是比较好的。html
官方网站:http://projects.spring.io/spring-framework/前端
原理
DispatcherServlet类是spring mvc的核心控制器,负责分发和响应用户请求。java
DispatcherServlet请求处理工做流程以下图所示:web
一、用户将request请求发送至前端控制器(Front controller)ajax
二、前端控制器将请求转发至具体的业务控制器(Controller)spring
三、业务控制器建立业务逻辑实现(Service)和数据数据库
四、业务控制器(Controller)将结果返回给前端控制器(Front controller)json
五、前端控制器(Front controller)选择展现模板(View template)浏览器
六、最后将结果经过前端控制器(Front controller)返回给客户安全
DispatcherServlet继承于HttpServlet,因此它拥有HttpServlet全部特征。
加载依赖
因为本人惯用spring boot进行项目构建,因此配置默认都是spring boot的方式
只要在项目中依赖springframework的包就可使用Spring MVC
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.9.RELEASE</version> </dependency> </dependencies>
若是你使用spring boot来搭建项目,那么是不须要以上依赖的,由于springboot的依赖已经包含他了
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>1.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
DispatcherServlet拦截配置
DispatcherServlet的url-pattern默认状况下为“/”根路径,全部的url请求都会被DispatcherServlet处理。可是咱们能够对url-pattern进行配置。
在spring boot的配置文件application.properties中进行配置
#拦截全部以.do结尾的路径 server.servlet-path=*.do #拦截全部springmvc目录下的路径 server.servlet-path=/springmvc/*
这里须要注意,项目中的RequestMapping请求路径不能包含拦截内容。好比 拦截路径为“server.servlet-path=/springmvc/*“,RequestMapping为“/index”,那么请求路径为http://localhost:8090/springmvc/index
注解
@Controller
此注解声明了一个Controller层的类,使用此注解的类会被识别为一个控制器。
@Controller public class StartController { }
在此例子中咱们不用将类声明为一个bean,由于spring boot在初始化时使用了@ComponentScan注解进行自动扫描并注入。
@RestController
此注解声明一个类为Restful风格的控制器。其实就是@Controller和@ResponseBody两个注解叠加的效果。
@RestController public class StartController { @PostMapping(value = "/login1") public User login1(@RequestBody User user1) { User user = new User(); user.setUsername(user1.getUsername()); user.setPassword(user1.getPassword()); return user; } }
- @RestController注释的类中,全部的方法默认添加@ResponseBody,会将内容放在http主体中返回。
@RequestMapping
此注解声明了一个可访问的资源映射,url能够经过RequestMapping配置的映射路径来访问这个方法。
参数:
value(默认) | 访问该资源的URI路径。资源路径支持通配符访问。(如例5) 此参数能够不写则为默认访问。(如例1) 该参数能够设置URI形式的入参,入参使用{}进行表示。在方法参数中使用@PathVariable能够将URI参数映射给一个方法入参。(如例4) |
method | 指定http的提交类型。通常使用RequestMethod类来指定类型。 经常使用的基本上就是RequestMethod.GET和RequestMethod.POST。(如例二、3) |
consumes |
指定处理请求的提交内容类型(Content-Type),例如application/json, text/html; |
produces | 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;(如例6) 在作接口时每每使用此参数指定接口出参数据结构类型。 |
params | 指定request中必须包含某些参数值是,才让该方法处理。 |
headers | 指定request中必须包含某些指定的header值,才能让该方法处理请求。 |
括号内只写参数值,则表明此参数是默认参数的值。
例子:
@RequestMapping("/home") public class StartController { @RequestMapping public String index(Model model) { return "index"; } @RequestMapping(value = "/login",method = RequestMethod.GET) public String login(Model model) { return "login"; } @RequestMapping(value = "/login",method = RequestMethod.POST) public String loginPost(Model model) { return "login"; } @RequestMapping(value = "/{parameter}",method = RequestMethod.GET) public String parameter(@PathVariable("parameter") String urlParameter, Model model) { return "login"; } @RequestMapping(value = "/*/login",method = RequestMethod.GET) public String login(Model model) { return "login"; } @RequestMapping(value = "/login1", method = RequestMethod.POST, produces = MediaTypes.JSON_UTF_8) public String login1(Model model) { return "login"; } }
- RequestMapping能够标识一个类或一个方法,在类上时表明这个类内全部资源都在该路径下。在方法上时表明该方法的访问路径。如例2的路径为“/home/login”
- RequestMapping有一些变种注解,如@GetMapping、@PostMapping等。此类注解省去了method参数。@GetMapping至关于@RequestMapping(method = RequestMethod.GET)
@PathVariable
此注解用于获取URI形式的参数,参数做为路径的一部分被传递过来。
参数:
value(默认) | URI形式参数的名称。也就是@RequestMapping注解使用“{}”来标注的参数名称。 此参数不写,则要求方法入参名称与URI参数名称一致。(如例3) |
括号内只写参数值,则表明此参数是默认参数的值。(如例二)
例子:
@RequestMapping(value = "/{parameter}") public String parameter(@PathVariable(value = "parameter") String urlParameter, Model model) { return "login"; } @RequestMapping(value = "/{parameter}") public String parameter(@PathVariable("parameter") String urlParameter, Model model) { return "login"; } @RequestMapping(value = "/{parameter}") public String parameter(@PathVariable String parameter, Model model) { return "login"; }
- 更多关于URI参数的说明请参考官方文档:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-requestmapping-uri-templates
@RequestParam
得到request请求参数并绑定到方法参数上,get请求时使用此注解获取参数。
参数:
value(默认) | 请求参数名称。 此参数不写,则要求方法入参名称与请求参数名称一致。(如例2) |
required | 是否必输。默认状况下是true必输,若是但愿那个参数为非必输就设置成false(如例3) |
括号内只写参数值,则表明此参数是默认参数的值。(如例1)
例子:
//如下例子的url参数为?username=andy&password=111111 @GetMapping(value = "/login1") public String login1(@RequestParam("username") String username ,@RequestParam("password") String password) { return "login"; } @GetMapping(value = "/login2") public String login2(@RequestParam String username ,@RequestParam String password) { return "login"; } @GetMapping(value = "/login3") public String login3(@RequestParam String username ,@RequestParam(required=false) String password) { return "login"; } @GetMapping(value = "/login4") public String login4(@RequestParam Map user) { return "login"; }
- @RequestParam的参数可使用map接收,url的入参名和值,会以键值对的形式存储在map中(如例4)
@RequestHeader
获取request头信息。
参数:
value(默认) | 请求头参数名称。 此参数不写,则要求方法入参名称与请求头参数名称一致。(如例2) |
required | 是否必输。默认状况下是true必输,若是但愿那个参数为非必输就设置成false(如例5) |
括号内只写参数值,则表明此参数是默认参数的值。(如例1)
例子:
@GetMapping(value = "/login1") public String login1(@RequestHeader("Host") String host) { return "login"; } @GetMapping(value = "/login2") public String login2(@RequestHeader String Host) { return "login"; } @GetMapping(value = "/login3") public String login3(@RequestHeader("Accept-Encoding") List<String> encoding ) { return "login"; } @GetMapping(value = "/login4") public String login4(@RequestHeader Map<String,String> header) { return "login"; } @GetMapping(value = "/login5") public String login5(@RequestHeader(value = "Host",required=false) String host) { return "login"; }
- @RequestHeader可使用list接收一组用逗号分割的值(如例3)。如“gzip,deflate” 就会被list拆分接收。
- @RequestHeader可使用Map来接收全部的头信息,头信息会以键值对的形式存储在map中(如例4)。
@RequestBody
获取request请求,http主体内的参数,post请求时使用此注解获取参数。
参数:
required | 是否必输。默认状况下是true必输,若是但愿那个参数为非必输就设置成false(如例2) |
例子:
@PostMapping(value = "/login1") public String login1(@RequestBody User user) { return "login"; } @PostMapping(value = "/login2") public String login2(@RequestBody(required=false) User user) { return "login"; }
- @RequestBody将http主体中的数据转换到入参对象中(如例1)。
- http主体的形式由http Content Type定义。通常为application/json或application/xml
- @RequestBody入参接收对象中的属性名要求与http主体中的变量名一致。如:User类定义了usernam和password两个属性,那么json 形式的http body就应该写成{"username":"myuser","password":"111111"}
@ResponseBody
将响应内容直接放在http主体中返回。一般的@Controller方法返回的是视图名称,并跳转到这个视图。
@PostMapping(value = "/login1") @ResponseBody public User login1(@RequestBody User user1) { User user = new User(); user.setUsername(user1.getUsername()); user.setPassword(user1.getPassword()); return user; }
- @ResponseBody常常用于ajax请求和接口方法。由于ajax请求和接口方法要求直接返回内容而不是跳转到某一视图。
@SessionAttributes(不经常使用)
用于获取session中的参数。
@SessionAttributes做用于类的时候,会在方法执行结束时将对应名字的model内容存储到session中。(如例1)
@SessionAttributes做用于参数的时候,会取出session中对应名字的内容,赋值给当前的参数。(如例2)
参数:
value(默认) | session中的参数名称。 此参数不写,则要求方法入参名称与请求参数名称一致。(如例3) |
括号内只写参数值,则表明此参数是默认参数的值。(如例2)
例子:
@Controller @RequestMapping(value = "/home") @SessionAttributes("username") public class StartController { @PostMapping(value = "/login1") public String login1(HttpSession httpSession,Model model) { model.addAttribute("username","woshicanshu"); return "login"; } @PostMapping(value = "/login2") public String login2(@SessionAttribute("user") User user, HttpSession httpSession) { return "login"; } @PostMapping(value = "/login3") public String login3(@SessionAttribute User user, HttpSession httpSession) { return "login"; } }
@RequestAttribute(不经常使用)
获取request的参数。@RequestAttribute做用于参数的时候,会取出request中对应名字的内容,赋值给当前的方法入参。
参数:
value(默认) | request中的参数名称。 此参数不写,则要求方法入参名称与请求参数名称一致。(如例2) |
括号内只写参数值,则表明此参数是默认参数的值。(如例1)
例子:
@PostMapping(value = "/login1") public String login1(@RequestAttribute("username") String username,HttpRequest request) { return "login"; } @PostMapping(value = "/login2") public String login2(@RequestAttribute String username,HttpRequest request) { return "login"; }
@ModelAttribute(不经常使用)
将参数保存到Model模型中,供视图页面使用。
- 做用于参数时表示这个参数保存到model中。(如例1)
- 做用于方法时表示将这个方法的出参保存到model中,此方法会在执行任意一个@RequestMapping以前执行一次。(如例2)
参数:
value(默认) | model中的参数名称。 |
括号内只写参数值,则表明此参数是默认参数的值。(如例1)
例子:
//本例请求参数为 ?username=pltx @GetMapping(value = "/login1") public String login1(@ModelAttribute("username") String username,Model model) { return "login"; } @ModelAttribute("password") public String login2(String username) { return "000000"; }
@RequestPart(不经常使用)
用于获取使用multipart/form-data格式传递的http请求的请求体,一般用于获取上传文件。
@Autowired
用于在类中注入bean。
@Autowired private Activity2CompanyDao activity2CompanyDao;
@Repository
用于声明此类为一个数据库持久化类(DAO层)。
@Repository public class Activity2ConsumerCouponDaoImpl implements Activity2ConsumerCouponDaoCustom{ }
@Service
用于声明一个业务层的类。
@Service public class Activity2ConsumerService { }
Controller层
Controller层是项目的转向控制层,主要负责接收请求、转发请求到业务层(service)进行处理、将处理结果进行响应、控制页面跳转等职责。
须要注意涉及到业务逻辑的代码尽可能不要在Controller进行编写,将业务逻辑合理的封装在service层对项目的结构和复用性都是很是有益的。
Controller层主要经常使用的注解有@Controller、@RequestMapping、@Autowired、@RequestParam、@RequestHeader、@RequestBody、@ResponseBody等。
默认绑定的参数
Controller层的方法入参能够得到默认绑定的类的实例,这实例咱们能够经过形参的声明直接使用。其中主要包括HttpServletRequest、HttpservletResponse、HTTPSession、Model、ModelMap以及他们的衍生类。
HttpServletRequest
此参数能够得到一个HttpServletRequest实例。
@RequestMapping("/unauthorized") public String unauthorized(HttpServletRequest request, HttpServletResponse response) { }
HttpServletResponse
此参数能够得到一个HttpservletResponse实例。
@RequestMapping("/unauthorized") public String unauthorized(HttpServletRequest request, HttpServletResponse response) { }
HTTPSession
此参数能够得到一个HTTPSession实例。
@RequestMapping("/unauthorized") public String unauthorized(HTTPSession session) { }
Model/ModelMap
Model用于将模型数据传递到展现层,保存在Model中的数据能够直接在页面使用获取。
@RequestMapping(value = "/list", method = RequestMethod.GET) public String list(String name, Integer openType, Model model) { model.addAttribute("name", name); model.addAttribute("openType", openType); return "/activity2_company/list"; }
RedirectAttributes
model的Attribute参数传递的声明周期为一次请求。因此若是方法采用重定向到其余资源则Attribute保存的参数将会丢失,在页面是没法获取的。若是想要在重定向后在页面获取参数则须要使用 RedirectAttributes进行保存。
下面的例子在login页面仍然能够拿到message参数值。
@RequestMapping(value = "/logout", method = RequestMethod.GET) public String logout(RedirectAttributes redirectAttributes) { redirectAttributes.addFlashAttribute("message", "您已安全退出"); return "redirect:login"; } @RequestMapping(value = "/login", method = RequestMethod.GET) public String loginInput() { return "login"; }
RedirectAttributes中有两个添加参数的方法addAttribute和addFlashAttribute ,addAttribute参数会被放在url中进行传递,因此长度和类型会受到限制。而addFlashAttribute 参数放在flashmap内部对象中传递,对于长度和类型没有限制。
在重定向的方法中若是想要拿到,前面方法存入的addAttribute参数,只要在重定向方法入参加入这个参数便可
@GetMapping(value = "/login") public String login(RedirectAttributes redirectAttributes) { redirectAttributes.addAttribute("username","andy"); return "redirect:login1"; } @GetMapping(value = "/login1") public String login1(String username) { System.out.println(username); return "login"; }
在重定向的方法中若是想要拿到,前面方法存入的addFlashAttribute参数,则须要使用@ModelAttribute注解
@GetMapping(value = "/login") public String login(RedirectAttributes redirectAttributes) { redirectAttributes.addFlashAttribute("username","andy"); return "redirect:login1"; } @GetMapping(value = "/login1") public String login1(@ModelAttribute("username") String username) { System.out.println(username); return "login"; }
响应方式
返回到页面
Controller方法的出参直接写视图名称,则表明执行结束后调转到此视图。(加ResponseBody不行)
以下例将访问login页面
@GetMapping(value = "/login") public String login() { return "login"; }
跳转到其余Controller
Controller方法的出参能够经过增长forward和redirect前缀的方式进行转发或重定向到,其余Controller。
@GetMapping(value = "/login") public String login() { return "login"; } @GetMapping(value = "/login1") public String login1() { return "redirect:login"; } @GetMapping(value = "/login2") public String login2() { return "forward:login"; }
强调一下forward和redirect区别。forward是服务器转发,浏览器地址不变,服务器将请求的新地址内容返回给刘蓝鳍。redirect是浏览器重定向,浏览器地址改变,服务器告诉浏览器要访问新的地址后浏览器从新访问新地址。
输出到页面
咱们可使用HttpServletResponse对象将内容直接输出到页面
@GetMapping(value = "/login") public void login(HttpServletResponse response) { try { response.setHeader("Content-type", "text/html;charset=UTF-8"); response.getWriter().println("<h1>我是标题</h1>"); } catch (IOException e) { e.printStackTrace(); } }