JSD-2204-RESTful-Service-SpringMVC-Day06
1.关于RESTful(续)
在设计URL时,使用{}
的占位符时,可以在名称右侧添加:
,并在其右侧配置正则表达式,以对URL中的参数的基本格式进行约束,例如:
// http://localhost:9080/album/9527/delete
@RequestMapping("/{id:[0-9]+}/delete")
public String delete(@PathVariable Long id) {log.debug("开始处理删除id={}请求", id);return "处理了/" + id + "/delete的请求";
}
通过使用以上正则表达式,纯数字的id可以匹配以上路径,可以正常访问,如果不是纯数字的id,则根本匹配不到以上路径,以上方法也不会执行,服务器端将直接响应404错误。
提示:404错误相比400错误,能更早的回绝客户端的错误请求。
在使用{}
占位符且使用了正则表达式时,不冲突的匹配(每个URL只会匹配到其中某1个正则表达式,不会同时匹配到多个正则表达式)是可以共存的,例如:
// http://localhost:9080/album/9527/delete
@RequestMapping("/{id:[0-9]+}/delete")
public String delete(@PathVariable Long id) {log.debug("开始处理删除id={}请求", id);return "处理了/" + id + "/delete的请求";
}// http://localhost:9080/album/huawei/delete
@RequestMapping("/{name:[a-zA-Z]+}/delete")
public String delete(@PathVariable String name) {log.debug("开始处理删除name={}请求", name);return "处理了/" + name + "/delete的请求";
}
甚至,不使用正则表达式的,也可以与之共存,例如,在以上基础上,还可以添加:
// http://localhost:9080/album/test/delete
@RequestMapping("/test/delete")
public String delete() {log.debug("开始处理测试删除请求");return "处理了测试删除的请求";
}
Spring MVC在处理时,会优先匹配没有使用正则表达式的,所以,当提交 /album/test/delete
时,会成功匹配到以上delete()
方法,不会匹配到delete(String name)
方法。
在RESTful的建议中,对于不同的数据操作,应该使用不同的请求类型,例如:
GET >>> /albums/9
:对id值为9的相册数据执行查询(执行数据的select
操作)PUT >>> /albums/9
:对id值为9的相册数据执行编辑(执行数据的update
操作)DELETE >>> /albums/9
:对id值为9的相册数据执行删除(执行数据的delete
操作)POST >>> /albums
:新增相册数据(执行数据的insert
操作)
通常,绝大部分应用中,在处理业务时(并不是直接操作某数据),并不会采纳以上建议!
最后,在开发实践中,更多的还是只使用GET
和POST
这2种请求方式,关于RESTful 风格的URL设计参考:
- 查询列表:
/数据类型的复数
- 例如:
/albums
- 例如:
- 查询指定id的数据:
/数据类型的复数/id值
- 例如:
/albums/{id}
- 例如:
- 对指定id的数据进行某操作:
/数据类型的复数/id值/操作
- 例如:
/albums/{id}/delete
- 例如:
2.关于MVC
MVC = Model + View + Controller
MVC为设计软件提供了基本的思想,它认为每个软件都应该至少包含这3大部分,且各部分分工明确,只负责整个数据处理流程中的一部分功能。
例如V通常表现为“软件的界面”,用于呈现数据、提供用户操作的控件。
而C表示控制器,用于接收请求、响应结果,并不会处理实质业务。
而M表示数据模型,通常由业务逻辑和数据访问这2部分组成,在开发实践中,数据访问通常指的就是数据库编程,而业务逻辑是由专门的类来实现的,这样的类通常使用Service
作为类名的关键字。
在整个数据处理过程中,将会是:Controller调用Service,而Service调用Mapper。
业务逻辑的主要职责是:设计业务流程,处理业务逻辑,以保证数据的完整性和安全性。
3.开发Service
Service的开发规范是先写接口,再写实现类。
通常,会在项目的根包下创建service
子包,Service接口将存放在这个包中,并且,还会在service
包下创建impl
子包,Service实现类都将放在这个包中,实现类都会使用ServiceImpl
作为类名的后缀。
例如:在项目的根包下创建service.IAlbumService
接口,然后,再创建service.impl.AlbumServiceImpl
类,且此类将实现IAlbumService
接口。
为了保证项目启动时可以正确的创建此实现类,需要类上添加@Service
注解。
package cn.tedu.csmall.product.service;public interface IAlbumService {
}
package cn.tedu.csmall.product.service.impl;import cn.tedu.csmall.product.service.IAlbumService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class AlbumServiceImpl implements IAlbumService {public AlbumServiceImpl() {log.info("创建业务对象:AlbumServiceImpl");}}
假设需要实现:添加相册。
则在接口中添加抽象方法,关于抽象方法的设计:
- 返回值类型:当客户端提交了相应的请求到服务器端,业务逻辑层正确的处理了数据后,是否需要返回某个数据(设计返回值类型时,不需要考虑失败的情况,因为将通过抛出异常来表示失败)
- 方法名称:自定义
- 参数列表:所有应该由客户端提交的数据属性
void addNew(AlbumAddNewDTO albumAddNewDTO);
然后,在实现类中:
@Override
public void addNew(AlbumAddNewDTO albumAddNewDTO) {log.debug("开始处理【添加相册】的业务,参数:{}", albumAddNewDTO);// 调用AlbumMapper对象的int countByName(String name)方法统计此名称的相册的数量String name = albumAddNewDTO.getName();int countByName = albumMapper.countByName(name);log.debug("尝试添加的相册名称是:{},在数据库中此名称的相册数量为:{}", name, countByName);// 判断统计结果是否大于0if (countByName > 0) {// 是:相册名称已经存在,抛出RuntimeException异常String message = "添加相册失败!相册名称【" + name + "】已存在!";log.warn(message);throw new RuntimeException(message);}// 获取当前时间:LocalDateTime now = LocalDateTime.now()LocalDateTime now = LocalDateTime.now();// 创建Album对象Album album = new Album();// 补全Album对象中各属性的值:name:来自参数// 补全Album对象中各属性的值:description:来自参数// 补全Album对象中各属性的值:sort:来自参数BeanUtils.copyProperties(albumAddNewDTO, album);// 补全Album对象中各属性的值:gmtCreate:nowalbum.setGmtCreate(now);// 补全Album对象中各属性的值:gmtModified:nowalbum.setGmtModified(now);// 调用AlbumMapper对象的int insert(Album album)方法插入相册数据log.debug("即将向数据库中插入数据:{}", album);albumMapper.insert(album);
}
3.1关于业务异常
通常,建议自定义异常,用于表示在业务逻辑层中的“失败”(或错误),而不要使用已知的异常类型,避免捕获、处理不准确!
可以在项目的根包下创建ex.ServiceException
类,继承自RuntimeException
:
public class ServiceException extends RuntimeException {// 生成5个构造方法
}
4.Spring MVC统一处理异常
Spring MVC框架提供了统一处理异常的机制,使得每种类型的异常在处理时,只需要编写1次相关代码即可。
通常,统一处理异常的代码会写在专门的类中,此类应该添加@ControllerAdvice
,则类中相关的方法会在处理每个请求时生效!
由于目前采取前后端分离的模式,处理异常后的响应方式是响应正文,所以,还应该使用@ResponseBody
,或者,使用@RestControllerAdvice
,它同时具有@ControllerAdvice
和@ResponseBody
的效果。
@RestControllerAdvice
public class GlobalExceptionHandler {
}
然后,在此类中添加处理异常的方法:
- 注解:必须添加
@ExceptionHandler
注解,表示此方法是统一处理异常的方法 - 访问权限:应该使用
public
- 返回值类型:参考处理请求的方法
- 方法名称:自定义
- 参数列表:至少包含1个异常类型的参数,表示需要处理的异常,或理解为Spring MVC框架在调用控制器的方法后捕获的异常,另外,可按需添加
HttpServletRequest
、HttpServletResponse
等少量特定类型的参数
所以,完整的处理异常的代码为:
package cn.tedu.csmall.product.ex.handler;import cn.tedu.csmall.product.ex.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandlerpublic String handleServiceException(ServiceException e) {log.debug("处理ServiceException:{}", e.getMessage());return e.getMessage();}}
并且,在任何控制器类中,都不必再处理ServiceException
了。
另外,在以上类中,可以同时存在多个处理不同异常的方法(允许多个处理的异常之间存在继承关系)!
建议在每个项目中,在统一处理异常的类中,都添加对Throwable
的处理,以保证所有异常都会被处理,粗糙的异常信息不会响应到客户端去!
package cn.tedu.csmall.product.ex.handler;import cn.tedu.csmall.product.ex.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandlerpublic String handleServiceException(ServiceException e) {log.debug("处理ServiceException:{}", e.getMessage());return e.getMessage();}@ExceptionHandlerpublic String handleThrowable(Throwable e) {log.debug("处理Throwable");e.printStackTrace();return "程序运行过程中出现意外错误,请联系系统管理员!";}}
4.1使用Spring Validation检查请求参数
Spring Validation框架的主要作用:实现了简化检查请求参数的基本格式
在Spring Boot中,需要添加spring-boot-starter-validation
依赖项。
当需要检查请求参数时,需要在处理请求的方法的参数列表中,对需要检查的参数添加@Validated
注解,表示此参数是需要通过Spring Validation进行检查的:
@RequestMapping("/add-new")
public String addNew(@Validated AlbumAddNewDTO albumAddNewDTO) {// 省略方法体的代码
}
然后,在类的属性上,添加相关检查注解,并在检查注解中配置message
属性以指定错误时的提示文本:
@Data
public class AlbumAddNewDTO implements Serializable {@NotNull(message = "必须提交相册名称!")private String name;private String description;private Integer sort;}
当Spring Validation检查不通过时,将抛出BindException
,所以,可以在统一处理异常的类中对此类异常进行处理:
@ExceptionHandler
public String handleBindException(BindException e) {log.debug("处理BindException:{}", e.getMessage());StringBuilder stringBuilder = new StringBuilder();List<FieldError> fieldErrors = e.getFieldErrors();for (FieldError fieldError : fieldErrors) {String message = fieldError.getDefaultMessage();stringBuilder.append(message);}return stringBuilder.toString();
}
除了@NotNull
以外,框架还提供了许多检查注解,
@Pattern
:通过此注解的regexp
属性配置正则表达式,并使用message
配置验证失败时的提示文本- 注意:此注解只能添加在字符串类型的属性上
- 注意:此注解不能检查“为
null
”的情况,如果不允许为null
,则必须同时配置@NotNull
和@Pattern
@Range
:通过此注解的min
和max
属性可以指定整型数据的最小值和最大值- 提示:此注解可以和
@NotNull
一起使用
- 提示:此注解可以和
周末作业
关于根据id删除数据,在处理业务时,应该先根据id查询数据,检查此数据是否存在,然后再删除。
完成各数据的添加和根据id删除,包含Mapper层、业务逻辑层、控制器层。
JSD-2204-RESTful-Service-SpringMVC-Day06相关推荐
- [转]构建基于WCF Restful Service的服务
本文转自:http://www.cnblogs.com/scy251147/p/3566638.html 前言 传统的Asmx服务,由于遵循SOAP协议,所以返回内容以xml方式组织.并且客户端需要添 ...
- 在IIS8.5的环境下配置WCF的Restful Service
今天在客户的环境中(Windows Server 2012 R2 + IIS 8.5)搭建Call WCF Restful Service的功能,发现了几个环境配置的问题,记录如下: 1):此环境先安 ...
- 框架:SpringBoot构建Restful service完成Get和Post请求
SpringBoot构建Restful service完成Get和Post请求 一个基本的RESTful service最经常向外提供的请求Method就是Get和Post. 在Get中,常用的都会 ...
- 开源的库RestSharp轻松消费Restful Service
现在互联网上的服务接口都是Restful的,SOAP的Service已经不是主流..NET/Mono下如何消费Restful Service呢,再也没有了方便的Visual Studio的方便生产代理 ...
- REST 之 Spring 4 RESTful service
2019独角兽企业重金招聘Python工程师标准>>> 请参考阅读 http://www.ibm.com/developerworks/library/wa-restful/ the ...
- Restful Service 中 DateTime 在 url 中传递
在C# url 中一旦包特殊字符,请求可能就无法送达.可以使用如下方法,最为便捷. 请求端: beginTime.Value.ToString("yyyyMMddHHmmss") ...
- c++ python混合编程 restful_How to use Python to build a RESTful Web Service
由于知乎目前限制单人仅能开通单个专栏,所以关于文章主题的所有文字都会写在该单篇文章中(避免污染专栏),目前处于长篇连载且停滞状态,待续.. Github Repo: nekocode/tornaRES ...
- RPC和Restful深入理解
一.RPC RPC 即远程过程调用(Remote Procedure Call Protocol,简称RPC),像调用本地服务(方法)一样调用服务器的服务(方法).通常的实现有 XML-RPC , J ...
- SpringBoot2.x系列教程38--整合JAX-RS之利用Jersey框架实现RESTful
SpringBoot2.x系列教程38--整合JAX-RS之利用Jersey框架实现RESTful 作者:一一哥 一. JAX-RS与Jersey简介 1. JAX-RS简介 在Java EE 6 中 ...
- java smart算法_Java Restful API 文档生成工具 smart-doc
谁说生成api文档就必须要定义注解? 谁说生成接口请求和返回示例必须要在线? 用代码去探路,不断尝试更多文档交付的可能性. 如果代码有生命,为什么不换种方式和它对话! 一.背景 没有背景.就自己做自己 ...
最新文章
- 解决Kali LinuxVI编辑器无法复制问题
- c#中位运算符的运用
- BlackBerry 开发笔记入门 控件简介
- Block的循环引用详解
- Python + GitHub Actions 实现 CSDN 自动签到与抽奖(非 selenium 版本)
- python 自动上报json信息_python接口自动化5-Json数据处理
- 已知矩阵 matlab,在MATLAB中,已知矩阵A,那么A(:,2:end)表示
- Tomcat BIO . NIO . ARP 配置
- 数据结构c语言程海英上机,数据结构(C语言版)程海英-上机6.doc
- linux下redis安装教程
- lsp语言服务器,身为程序员还不知道?Xtext与LSP让一个语言服务器横扫多个IDE!-lsp文件...
- PHP集成腾讯云短信SDK
- HttpClient4.X发送Get请求的url参数拼接
- 如何用spss客户端和SPSS AU在线进行单样本T检验操作?
- no valid sudoers sources found, quitting
- 沟通和编程一样,也是一门艺术系列1(最佳的沟通态度)
- 1034. 边框着色
- Python整数进制间转换
- 使用Direct3D实现如幻灯片的动态图片切换效果
- 蚂蚁员工激励达到1376.9亿元 人均可在杭州买一套283平房子
热门文章
- mysql outer join的用法_MySQL 8 中的连接语法JOIN、OUTER JOIN的相关用法
- 华为鸿蒙系统支持旧机型,华为鸿蒙系统2.0来了! 华为鸿蒙2.0系统支持手机机型...
- java数字金额大写金额_Java实现 “ 将数字金额转为大写中文金额 ”
- iOS控件设置虚线框
- vue 打印出现多余空白页的情况
- C++-二分查找库函数
- Text to image论文精读GR-GAN:逐步细化文本到图像生成 GRADUAL REFINEMENT TEXT-TO-IMAGE GENERATION
- 香肠派对学计算机,香肠派对电脑版:雷电模拟器教你轻松吃鸡
- 考研数学多重积分计算秒杀(对称性化简以及雅可比球坐标)
- 最全解读西门子MES/MOM平台Opcenter,100多亿美金的数字化之路