在上篇Spring MVC入门篇中,咱们初步了解了Spring MVC开发的基本搭建过程,本文将针对实际开发过程的着重点Controller部分,将经常使用的知识点罗列出来,并配以示例。在这以前,咱们有必要回顾一下,Spring MVC在咱们的WEB开发中,定位或者做用是什么?Spring MVC在项目中,主要做用是接收客户端请求、解析路径并分发请求到相应的控制器即Controller中执行相应方法,在方法中,咱们常见的操做有,调用业务逻辑层(后面会介绍到)方法,访问数据库,获取数据或者更新数据,若是是获取数据通常是要返回给前端,经常使用方式有两种:1.传统的Jsp开发中,咱们能够将数据封装到Model属性中,而后在页面中经过el表达式之类的方式获得;2.随着Ajax技术/RESTful风格的兴起,一样能够在先后端分离的状况下传递数据(RESTful基础学习阶段能够不做重点,但Ajax必定要掌握)。另外基于Spring MVC的开发模式下,参数的获取、匹配,以及页面的跳转都十分方便,下面咱们就来实践操做一下。html
若是学习阶段习惯将Jsp文件直接放在web文件根目录webapp下,建议如今开始转变,将其分类放置WEB-INF下,这样一来,咱们但愿访问一个页面,将再也不是直接经过路径去访问,而是经过Spring MVC中的请求,匹配到相应控制器中方法内部,再跳转至相应页面。区别在于WEB-INF下文件针对服务器端,而客户端例如浏览器是没法直接访问的,这样能够减小直接访问的风险,另外即便抛开安全性隐蔽性不谈,须要填充Model传递数据的Jsp页面若是在直接访问的状况下,可能会出现各类奇奇怪怪的问题,空白、无数据、样式错乱等等。页面跳转SpringMVC默认是请求转发,本文主要针对请求部分,均做默认请求转发处理。前端
@Controllerweb
该注解用于Spring识别并实例化控制器bean到上下文中,即加上这个注解的类Spring才能识别知道它是要做为控制器。spring
@RequestMapping数据库
该注解既可用于类上也能够用在方法上,实际开发每每二者都会用到,用于匹配url路径,接收请求,只有匹配的请求才会进入该控制器执行相关方法。后端
@RequestParam浏览器
在控制器方法中,用于将注入的参数与前台请求参数绑定spring-mvc
@PathVariable安全
用于绑定url路径中占位的参数服务器
登陆应该是你们再熟悉不过的web程序操做,这里以用户名、密码为例,分别对应实体类User中属性username和password,那么咱们的页面表单部分以下所示:
login.jsp中
<form action="${pageContext.request.contextPath }/user/login" method="post"> 用户名<input type="text" name="username" /><br/> 密码<input type="password" name="password" /><br/> <button type="submit">登陆</button> </form>
Controller代码
package com.mmm.web; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("user") public class DemoController { @RequestMapping(value="/toLogin") public String toLogin() { return "login"; } @RequestMapping(value="/login") public String login(String username,String password) { System.out.println("用户名---" + username); System.out.println("密码---" + password); return "index"; } }
有了前面的文件路径问题,这里咱们先定义一个toLogin方法用于访问登陆页面login.jsp,而后在页面表单点击提交后会请求到这里的login方法,重点:form表单中输入框<input>的name属性值,对应Controller中方法的参数名,即这里login方法的两个参数名,username和password,经过这两处的值,Spring MVC便可自动匹配使咱们轻松获取参数。
启动Tomcat,在地址栏输入http://localhost/spring-mvc/user/toLogin,便可访问到登陆页面,以下所示
任意输入用户名和密码内容后,点击登陆,便可看到eclipse控制台输出相似以下信息
并跳转至index.jsp页面,这里即成功获取到了前台传递来的参数,这种方式十分方便,但并非惟一,因此下面分别介绍其它的方法。
***基于以前学过的Servlet系列的请求对象HttpServletRequest,它有一个getParameter(String parameterName)方法,这个parameterName即前台参数名,这里即一样对应输入框<input>的name属性值。
***应用Spring MVC的机制,经过实体类装配属性,一样能够匹配到参数,这里的用户名和密码,每每是对应实体类这里以User为例,类中有username和password这2两个字符串属性。这样一来,经过User对象咱们也能够匹配到前台的这两个参数。
下面咱们汇总上面的内容,修改login方法为以下所示
@RequestMapping(value="/login") public String login(String username,String password, HttpServletRequest req,User user) { System.out.println("直接参数名匹配获取:用户名---" + username); System.out.println("直接参数名匹配获取:密码---" + password); System.out.println("HttpServletRequest获取:用户名---" + req.getParameter("username")); System.out.println("HttpServletRequest获取:密码---" + req.getParameter("password")); System.out.println("User获取:用户名---" + user.getUsername()); System.out.println("User获取:密码---" + user.getPassword()); return "index"; }
再次访问登陆页面,输入内容并点击登陆后,便可看到eclipse控制台输出相似以下信息
代表以上方式都可用于获取前台传递参数值。
PS:上面第一种方式(也是经常使用方式中)若是前端表单中name值和我这里方法中的参数名确实不同,有没有别的办法能解决这个问题?目前Spring MVC各方面的注解渐渐在完善,这里Spring MVC就为咱们提供了这样一种注解,@RequestParam,用于指定前台参数名,即这里若是咱们将上面登陆页面中的密码输入框的name属性值改成pwd,以下所示
密码<input type="password" name="pwd" /><br/>
按照前面咱们的参数名匹配,Controller的login方法中是password,前台是pwd,这样是匹配不上,随之也没法获取数据的。可是引入上面提到的注解,方法能够中参数能够将String password修改成:@RequestParam("pwd") String password,这样一来,便可成功获取数据了。
上面结合表单示例介绍了几种方式获取请求参数,以前学习Servlet部分,应该都熟悉doPost和doGet方法,这里的表单每每就是用的post请求方式提交。
使用post提交时,数据将以数据块的形式提交到服务器,URL地址栏中不会出现数据,因此用这种方式提交的表单数据是相对安全的。因此表单提交包含相似于密码等数据时,建议使用post方法。
使用get提交时地址栏上会在你当前项目路径后加上相似?pram1=value1¶m2=value2”的形式,将表单数据附加到URL的后面,提交到服务器处理,这种方式效率更高,因此在没有私密数据时,请求推荐这种。
除了上面提到的方式,还有一种获取路径传参的方式,这里也介绍一下,比较实用,经过@PathVariable注解,经过url路径实现动态传参并获取参数值,代码以下示例:
@RequestMapping(value="/show/{id}") public String show(@PathVariable(value="id") String str) { System.out.println("url获取:id参数值---" + str); return "index"; }
而后,咱们在地址栏中输入localhost/spring-mvc/user/show/abcdefg,路径末尾的abcdefg即对应上面Controller代码@RequestMapping(value="/show/{id}")中的id,咱们经过{id}这个大括号加参数名的方式去动态接收它,不论你的值是多少,这里就是用id变量来对应,因而下面@PathVariable(value="id")中的id即与之相应,随后绑定到String str上,这个str即匹配该参数值,咱们即可以获取到该数据了。输入地址后回车,便可看到控制台,输出以下:
前面提到的get、post主要是讲前台请求方式,name咱们后台是否能够选择接受指定方式的请求呢?固然是能够的。@RequestMapping的属性中有个method,英文是方法的意思,在这里用于指定要接收的请求方式,以下所示
为了方便,Spring MVC还为咱们提供了RequestMethod枚举,以下所示
* @author Juergen Hoeller * @since 2.5 * @see RequestMapping * @see org.springframework.web.servlet.DispatcherServlet#setDispatchOptionsRequest * @see org.springframework.web.servlet.DispatcherServlet#setDispatchTraceRequest */ public enum RequestMethod { GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE }
其中指定了各类请求方式,咱们能够直接经过例如RequestMetho.GET来指定。
例如上面的登陆部分,咱们首先要前往登陆页面,请求并无参数传递,因此咱们直接经过get方式请求,而后在登陆页面中输入信息后点击登陆,提交表单登陆时,咱们每每用post。上面咱们的@RequestMapping(value="")这个value值一个是toLogin,一个是login,两个不一样的值,就是为了区别这两个请求,可是实际上是能够写成同样的,这里咱们稍做修改成以下:
@RequestMapping(value="/login",method=RequestMethod.GET) public String toLogin() { return "login"; } @RequestMapping(value="/login",method=RequestMethod.POST) public String login(String username, String password) { System.out.println("直接参数名匹配获取:用户名---" + username); System.out.println("直接参数名匹配获取:密码---" + password); return "index"; }
这样咱们一样能够实现前面的效果。
在没有应用maven时,以前常用下面的方式新建web项目。
咱们首先要理清的是,咱们的web项目都是动态的( dynamic),这个动态最上层,是客户端的各类动态操做,深刻到底层,大多会反映到数据库,那么二者有什么关联,或者是怎样关联起来的?其中上面讲到的请求参数每每就是一个中间人。以上面的登陆为例,客户端经过表单提交了用户名和密码两个参数,那么咱们究竟是要到数据库中查询有没有帐号和密码都同时匹配的用户记录,有的话表明输入正确,没有的话则表明输入信息有误。客户端获得的登陆成功或者失败这种不肯定的结果,基于他的输入,也基于数据库中数据,无数个相似这样的关联关系个构建起了咱们的web项目业务逻辑结构。
因此后面咱们就要理清什么是业务逻辑了。在登陆过程当中,咱们验证用户名和密码是否正确,会调用到用户的持久层对象,去查询数据库用户表记录;可是同时咱们须要记录登陆信息,即在日志表中插入一条登陆信息。可是持久层有查询用户表的方法,也有插入日志信息的方法,可是两种方法一块儿调用的并无,因此这里须要咱们在控制层和持久层之间添加一层业务逻辑层,整合这些持久操做,封装好业务逻辑方法供控制层调用。
固然这里举例日志可能有点不太恰当,由于基于Spring AOP,例如事务管理、日志信息记录等通用组件能很方便的实现,能让咱们专一于实现项目中的业务逻辑,可是总的来讲,这里能够先简单的理解为,业务逻辑Service层,做用于持久层(dao)和控制层(controller)之间,它每每用于组装比持久层更复杂的操做过程,而且也不局限于数据库操做,而后供控制层调用,控制层则是专一于接收请求,分发到相应业务逻辑方法进行处理,而后做出响应。
以上讲到了Spring MVC通用请求相关的处理参数过程及方法,固然还有例如文件上传也是一种特殊的请求,而且经常使用到,后面会理出来。咱们在实际开发中每每下功夫最多的是如何实现那些复杂的业务逻辑,相反控制层不该该做用到这些业务处理。因此下面会专门理清一下业务逻辑层的部分,经过注入前面咱们学习的MyBatis封装的持久对象,而后将业务逻辑层对象注入到控制层,实现Spring MVC与MyBatis的整合。