文章目录
一、RESTFUL 的设计风格
1、RESTFUL 概述
2、RESTFUL 设计风格示例
二、SpringMVC 拦截器
1、SpringMVC 拦截器使用步骤
三、SpringMVC 文件上传和下载
1、SpringMVC 上传文件
2、SpringMVC 文件下载
一、RESTFUL 的设计风格
1、RESTFUL 概述
(1)RESTFUL 是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次。在RESTFUL的设计中服务器的任何内容都被当成资源来处理,例如网页、文件、数据库的数据等等,而同一种资源共享同一个接口地址,然后再通过请求方式的不同来区分对资源进行的不同操作。
(2)请求方式如下:
GET请求表示获取数据
POST请求表示新增数据
PUT/PATCH请求表示修改数据
DELETE请求表示删除数据
结合请求地址来看:
GET方式发送 /users请求时,表示查询users的所有数据
DELETE方式发送/users请求时,则表示删除users数据
POST方式发送/users请求时,则表示要新增一个用户数据
PUT方式发送/users请求时,则表示要更新一个用户数据
PATCH方式发送/users请求时,则表示要更新一个用户数据中的部分字段
2、RESTFUL 设计风格示例
(1)SpringMVC 提供了对RESTFUL的支持,这种支持体现在两个方面,SpringMVC 在进行请求地址映射时,不但会匹配请求地址的名称,而且还会匹配发送请求的方式,也就是说只有当请求地址和请求方式都匹配时,才能执行业务控制器中的方法。例如:
@RequestMapping(value="user",method= {RequestMethod.GET}) public ResultModel selectAll(){ return null; }
另外@RequestMapping()还可以用对应的请求方式代替,如:
@GetMapping("user") public ResultModel selectAll(){ System.out.println("查询所有"); System.out.println(us.selectAll()); return new ResultModel(us.selectAll(),null,"success",null); }
GET请求对应@GetMapping
POST请求对应@PostMapping
PUT/PATCH对应@PutMapping
DELETE对应@DeleteMapping
(2)在上述的请求地址映射中,客户端通过get方式发送user请求能够执行业务控制器方法,但是如果使用了除get以外的其他请求方式,就不能够执行该方法,这个设置为同一个地址不同请求方式提供了支持。SpingMVC在请求地址中可以提供占位符,而且占位符中的数据可以在方法中获取到,这就提供了一种非常简洁的传参方式。
例如:
@GetMapping("user/{userId}") public ResultModel selectById(@PathVariable("userId")int userId){ return null; }
通过上述配置,我们就可以在页面发送get方式的请求user/1表示要查询id为1的用户数据。
以下是RESTFUL所设计的一组接口(增删改查):
@RestController public class UsersController { @Resource private UsersService us; //业务层对象,便于调用业务层对应方法 //定义请求地址映射第一种:@RequestMapping(value="user",method= {RequestMethod.GET}) //定义请求地址映射第二种:@GetMapping("user"),下面都使用第二种 @GetMapping("user") public ResultModel selectAll() throws Exception { return new ResultModel(us.selectAll(),null,"success",null); } @GetMapping("user/{userId}") public ResultModel selectById(@PathVariable("userId")int userId) throws Exception{ return new ResultModel(null,us.selectById(userId),"success",null); } @PostMapping("user") public ResultModel insert(@Validated Users users,BindingResult br) throws Exception { //自定义参数校验异常判断,参数不对的时候会执行自定义异常的报错 if(br.hasErrors()) { throw new ParamException(); } us.insert(users); return new ResultModel(null,null,"success",null); } @PutMapping("user") public ResultModel updateById(@Validated Users users,BindingResult br) throws Exception { if(br.hasErrors()) { throw new ParamException(); } us.updateById(users); return new ResultModel(null,null,"success",null); } @DeleteMapping("user/{userId}") public ResultModel deleteById(@PathVariable("userId")int userId) throws Exception { us.deleteById(userId); return new ResultModel(null,null,"success",null); } }
(3)如果是PUT请求,需要添加一个额外的过滤器,控制器中才能获取到传递的参数。
<filter> <filter-name>HttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class> </filter> <filter-mapping> <filter-name>HttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
接口的请求地址设计好之后,我们还需要统一对返回的JSON数据进行规范,通常可以定义一个返回值类,在返回值类中封装执行状态以及一些需要返回给前端的数据。
(4)在AJAX的项目中也可以使用异常处理器进行统一的异常处理,但是要注意的是,在异常处理器中响应视图信息时必须响应JSON类型的视图信息。
代码如下:需要导入 fastjson 的 jar 包
@Component public class ExceptionResolver implements HandlerExceptionResolver{ @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object object, Exception ex) { FastJsonJsonView view = new FastJsonJsonView(); ex.printStackTrace(); Map<String, Object> map = new HashMap<String, Object>(); map.put("code", "error"); if(ex instanceof ParamException) { map.put("message", "参数错误"); }else { map.put("message", "服务器异常"); } view.setAttributesMap(map); ModelAndView mav = new ModelAndView(); mav.setView(view); return mav; } }
(5)前端请求类
<body> <a href="javascript:" οnclick="selectAll()">查询所有</a> <table id="table"> <tr> <td>姓名</td> <td>密码</td> <td>操作</td> </tr> </table> <form id="insert-form"> <input name="userName"><br> <input type="password" name="userPassword"><br> <input type="button" οnclick="insert()" value="新增"> </form> <input id="userId" placeholder="请输入用户id"><input type="button" value="搜索用户" οnclick="selectById()"> <form id="update-form"> <input name="userId"> <input name="userName"><br> <input type="password" name="userPassword"><br> <input type="button" οnclick="updateById()" value="修改"> </form> <script type="text/javascript"> function selectAll(){ $.ajax({ url: "/SpringMVC_Demo1/user", type: "get", dataType: "json", success:function(data){ for(var i=0;i<data.list.length;i++){ $("#table").append("<tr id='deleted"+data.list[i].userId+"'>"+ "<td>"+data.list[i].userId+"</td>"+ "<td>"+data.list[i].userName+"</td>"+ "<td>"+data.list[i].userPassword+"</td>"+ "<td><a href='javascript:' οnclick='deleteById("+data.list[i].userId+")'>删除</a></td>"+ "</tr>"); } } }); } function deleteById(userId){ $.ajax({ url: "/SpringMVC_Demo1/user/"+userId, type: "delete", dataType: "json", success:function(data){ console.log(data.code); $("tr[id=deleted"+userId+"]").remove(); } }); } function insert(){ $.ajax({ url: "/SpringMVC_Demo1/user", type: "post", data: $("#insert-form").serializeJSON(), dataType: "json", success:function(data){ console.log(data.code); } }); } function updateById(){ $.ajax({ url:"/SpringMVC_Demo1/user", type:"put", data:$("#update-form").serializeJSON(), dataType:"json", success:function(data){ console.log(data.code); } }); } function selectById(){ $.ajax({ url:"/SpringMVC_Demo1/user/"+$("#userId").val(), type:"get", dataType:"json", success:function(data){ $("#update-form input[name=userId]").val(data.object.userId); $("#update-form input[name=userName]").val(data.object.userName); $("#update-form input[name=userPassword]").val(data.object.userPassword); } }); } </script> </body>
二、SpringMVC 拦截器
Spring Web MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
1、SpringMVC 拦截器使用步骤
(1)拦截器定义,实现 HandlerInterceptor 接口
@Component public class Interceptors implements HandlerInterceptor{ /** * 请求处理之前调用拦截器 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("请求处理之前"); //返回true表示放行,返回false表示拦截 return true; } /** * 请求处理之后 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("请求处理后"); } /** * 请求处理之后,提交到界面之前 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("请求处理后,提交数据到界面之前"); } }
preHandle方法在执行处理器之前执行,可以用于登录验证、权限验证等等
postHandler方法在出行完处理器之后,进入视图解析器之前执行,可以对视图进行处理
afterCompletion方法在响应视图之前执行,主要用于关闭资源
(2)如果没有在拦截器类上面添加@Component注解,则需要手动配置拦截器,在 SpringMVC 的配置文件中添加标签加载拦截器
<!-- 配置拦截器 --> <bean id="Interceptors" class="com.springmvc.interceptor.Interceptors"/> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/js/**"/> <!--配置从根目录下发送的以js开头的所有请求不进入拦截器 --> <ref bean="Interceptors"/> </mvc:interceptor> </mvc:interceptors>
Springmvc 不会拦截.jsp的请求,但是会拦截静态资源请求,如果不想让用户直接访问 jsp 页面,需要将 jsp 页面放到 web-inf 中,对于静态资源需要提供静态资源处理器以及通过<mvc:exclude-mapping path="/js/**"/>对静态资源放行。
三、SpringMVC 文件上传和下载
无论是 Servlet 文件上传,Struts2 文件上传还是 SpringMVC 文件上传,前端是不变的既可以使用普通的表单上传也可以使用AJAX上传。区别主要在于后端代码的处理。
1、SpringMVC 上传文件
(1)加载多部件解析器
<!-- 配置多部件解析器 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设置上传文件的最大字节数 --> <property name="maxUploadSize" value="20971520"/> <property name="defaultEncoding" value="UTF-8"/> </bean>
(2)页面采用表单提交或者AJAX提交
<form action="upload.do" method="post" enctype="multipart/form-data"> <input type="file" name="head"><input type="submit" value="点击上传"> </form>
(3)SpringMVC 上传可以使用 commons-upload 的包来简化操作
(4)Controller 中处理文件
@Controller public class FileController { @RequestMapping("upload") @ResponseBody public String upload(MultipartFile head) throws Exception { //获取上传文件的名称 String filename=head.getOriginalFilename(); //获取文件的后缀 String suffix=filename.substring(filename.lastIndexOf(".")); //随机生成文件保存时的名字 String name=UUID.randomUUID().toString().replace("-", ""); filename=name+suffix; //获取保存文件的文件夹 String path = request.getServletContext().getRealPath("/upload"); File dir = new File(path); //判断目标文件夹是否存在,不存在则创建 if(!dir.exists()){ dir.mkdirs(); } //生成目标文件夹 File file=new File(dir,filename); //保存文件 head.transferTo(file); //在后端直接发送一个前端页面的弹窗 return "<script>alert('ok nb')</script>"; } }
2、SpringMVC 文件下载
(1)文件下载核心代码
// 设置响应头,响应类型为附件,浏览器将会用下载的方式处理响应的信息 response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(filePath, "UTF-8"));
(2)示例
① Controller 层 @Controller public class FileController { @RequestMapping("download") public void download(String filename,HttpServletResponse response) throws Exception{ //获取下载文件所在地址和文件名,拼接成下载路径 FileInputStream fis=new FileInputStream("D:\\upload\\"+filename); //下载文件核心代码 response.setHeader("content-disposition", "attachment;filename="+ URLEncoder.encode(filename, "UTF-8")); //创建输出流写入文件 OutputStream os=response.getOutputStream(); byte[] b=new byte[1024]; int length=0; while((length=fis.read(b))>0) { os.write(b, 0, length); } fis.close(); os.close(); } }
② 前端发送请求简单示例
<a href="download.do?filename=1.zip">点击下载</a>