草庐IT

SpringBoot(八) - 统一数据返回,统一分页工具,统一异常处理 (生成随机数,正则校验)

xiaoqigui 2023-04-16 原文

1、统一数据返回

使用逆向工程来进行测试,实体,mapper等省略;

1.1 直接使用 RequestResoult

1.1.1 RequestResoult 请求结果返回实体

//统一返回 实体 类
@Data
public class RequestResult<T> {

    //状态码
    private String code;

    //状态说明,对code的说明
    private String msg;

    //接口数据
    private T data;

}

1.1.2 service层

1.1.2.1 接口
public interface EdocEntryService {

    //按摘要查询
    List<EdocEntry> getEdocEntriesBySummary(String summary);
    
}
1.1.2.2 实现类

注意记得在 主启动类中添加 mapper接口扫描注解 :@MapperScan("com.kgc.sbt.mapper")

@Service
public class EdocEntryServiceImpl implements EdocEntryService {

    @Autowired(required = false)
    private EdocEntryMapper edocEntryMapper;

    @Override
    public List<EdocEntry> getEdocEntriesBySummary(String summary) {

        //使用逆向工程,封装查询条件

        EdocEntryExample edocEntryExample = new EdocEntryExample();

        //排序条件
        edocEntryExample.setOrderByClause(" id desc ");

        //根据摘要 模糊查询
        edocEntryExample.createCriteria().andSummaryLike("%" + summary + "%");

        //调用持久层 查询数据
        return edocEntryMapper.selectByExample(edocEntryExample);

    }
    
}

1.1.3 测试请求

@Slf4j
@RestController
public class EdocEntryController {

    @Autowired
    private EdocEntryService edocEntrieService;

    //根据电子文档,查询文档列表,直接使用 RequestResult
    @GetMapping("/edocEntries")
    //指定请求返回类型 RequestResult<List<EdocEntry>> 
	//public RequestResult<List<EdocEntry>> edocEntries(@RequestParam(required = false) String summary){ 
    //自适应请求返回类型 RequestResult<?>
    public RequestResult<?> edocEntries(@RequestParam(required = false) String summary){
        
        //调用业务接口,获取文档列表,进行统一返回
        //创建统一返回对象
        //每次都需要创建返回对象,代码冗余,不利于维护
        RequestResult<List<EdocEntry>> requestResult = new RequestResult<>();
        requestResult.setCode("200");
        requestResult.setMsg("success");
        List<EdocEntry> edocEntriesBySummary = edocEntrieService.getEdocEntriesBySummary(summary);
        log.info("{}",edocEntriesBySummary);
        requestResult.setData(edocEntriesBySummary);
        //接口统一返回查询结果
        return requestResult;
        
    }

}

测试结果:

1.2 使用 ResultBuildUtil 结果对象构建工具

1.2.1 CommonConstant 常量类

//Description: 系统常量类,统一管理项目中所有的常量
public class CommonConstant {

    /*
     统一返回成功的状态码
     */
    public static final String UNIFY_RESULT_SUCCESS_CODE = "200";

    /*
     统一返回成功的信息
     */
    public static final String UNIFY_RESULT_SUCCESS_MSG = "SUCCESS";

    /*
   统一返回错误的状态码
   */
    public static final String UNIFY_RESULT_FAIL_CODE = "999";

    /*
     统一返回错误的信息
     */
    public static final String UNIFY_RESULT_FAIL_MSG = "FAIL";


    /*
        分页默认页吗
     */
    public static final int DEFAULT_INIT_PAGE_NO = 1;

    /*
        分页默认条数
     */
    public static final int DEFAULT_INIT_PAGE_SIZE = 3;

}

1.2.2 ResultBuildUtil结果对象构建工具列

//Description: 结果构建工具类
public class ResultBuildUtil {

    //构建成功返回,支持任意类型参数
    public static <T> RequestResult<T> success(T t) {
        //创建统一返回成功结果对象
        RequestResult<T> requestResult = new RequestResult<>();

        requestResult.setCode(CommonConstant.UNIFY_RESULT_SUCCESS_CODE);
        requestResult.setMsg(CommonConstant.UNIFY_RESULT_SUCCESS_MSG);
        requestResult.setData(t);

        return requestResult;

    }

    //构建成功返回,空参
    public static <T> RequestResult<T> success() {
        return success(null);
    }

    //构建 失败返回,支持任意类型参数,用户不便于归类的异常错误结果返回
    public static <T> RequestResult<T> fail(T t) {
        //创建统一返回失败结果对象
        RequestResult<T> requestResult = new RequestResult<>();

        requestResult.setCode(CommonConstant.UNIFY_RESULT_FAIL_CODE);
        requestResult.setMsg(CommonConstant.UNIFY_RESULT_FAIL_MSG);
        requestResult.setData(t);

        return requestResult;

    }

    //构建 失败返回,空参
    public static <T> RequestResult<T> fail() {
        //创建统一返回失败结果对象
        return fail(null);

    }

    //构建 失败返回,自定义错误码,和说明,支持任意类型参数
    public static <T> RequestResult<T> fail(String errCode,String errMsg,T t) {
        //创建统一返回失败结果对象
        RequestResult<T> requestResult = new RequestResult<>();
        requestResult.setCode(errCode);
        requestResult.setMsg(errMsg);
        requestResult.setData(t);
        return requestResult;
    }

    //构建 失败返回,自定义错误码,和说明,无参
    public static <T> RequestResult<T> fail(String errCode,String errMsg) {
        //创建统一返回 失败结果对象
        RequestResult<T> requestResult = new RequestResult<>();
        requestResult.setCode(errCode);
        requestResult.setMsg(errMsg);
        return requestResult;
    }

}

1.2.3 service层

service层不变;

1.2.4 请求测试

@Slf4j
@RestController
public class EdocEntryController {

    @Autowired
    private EdocEntryService edocEntrieService;

    //根据电子文档,查询文档列表, 使用结果构建工具
    @GetMapping("/edocEntries")
    public RequestResult<?> edocEntries(@RequestParam(required = false) String summary){

        //使用结果构建工具,返回成功的结果
        return ResultBuildUtil.success(edocEntrieService.getEdocEntriesBySummary(summary));

    }

}

测试结果:

2、统一分页工具

2.1 PageSupport 统一分页工具类

// 分页 结果返回类
@Data
public class  PageSupport<T> {

    //当前页码
    private int pageNo;

    //页面条数
    private int pageSize;

   //总条数
    private int totalCount;

    //总页数
    private int totalPage;

    //分页数据
    private Collection<T> PageData;

    //当总条数确定时,总条数确定
    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;

        totalPage = totalCount % this.pageSize == 0
                ? totalCount / this.pageSize
                : totalCount / this.pageSize + 1;

    }

}

2.2 service 层

2.2.1 接口

public interface EdocEntryService {

    //条件分页查询
    PageSupport<EdocEntry> getEdocEntriesBySummary(String summary,Integer pageNo,Integer pageSize);
    
}

2.2.2 实现类

@Service
public class EdocEntryServiceImpl implements EdocEntryService {

    @Override
    public PageSupport<EdocEntry> getEdocEntriesBySummary(String summary, Integer pageNo, Integer pageSize) {

        //创建统一返回分页对象
        PageSupport<EdocEntry> pageSupport = new PageSupport<>();

        //设置分页参数
        pageSupport.setPageNo(pageNo < 1 ? CommonConstant.DEFAULT_INIT_PAGE_NO : pageNo);
        pageSupport.setPageSize(pageNo < 3 ? CommonConstant.DEFAULT_INIT_PAGE_SIZE : pageSize);

        //封装查询条件
        EdocEntryExample edocEntryExample = new EdocEntryExample();

        //排序条件
        edocEntryExample.setOrderByClause(" id desc ");

        //根据摘要 模糊查询
        edocEntryExample.createCriteria().andSummaryLike("%" + summary + "%");

        // 查询满足条件总条数
        pageSupport.setTotalCount((int) edocEntryMapper.countByExample(edocEntryExample));

        //增加分页参数
        edocEntryExample.setOffset((long)(pageSupport.getPageNo()-1)*pageSupport.getPageSize());
        edocEntryExample.setLimit(pageSupport.getPageSize());

        //增加分页数据
        pageSupport.setPageData(edocEntryMapper.selectByExample(edocEntryExample));

        //返回分页对象
        return pageSupport;
    }
  
}

2.3 commons-lang中 isEmpty 方法和idBlank区别

2.3.1 依赖

<!-- commons-lang start -->
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>
<!-- commons-lang end -->

2.3.2 isEmpty 方法和idBlank区别

isEmpty 和 isBlank ,isEmpty 方法和idBlank区别:只包含空格字符串判断,isEmpty是false,isBlank是true;
2.3.2.1 isEmpty
* <pre>
* StringUtils.isEmpty(null)      = true
* StringUtils.isEmpty("")        = true
* StringUtils.isEmpty(" ")       = false
* StringUtils.isEmpty("bob")     = false
* StringUtils.isEmpty("  bob  ") = false
* </pre>
2.3.2.2 isBlank
* <pre>
* StringUtils.isBlank(null)      = true
* StringUtils.isBlank("")        = true
* StringUtils.isBlank(" ")       = true
* StringUtils.isBlank("bob")     = false
* StringUtils.isBlank("  bob  ") = false
* </pre>

2.4 测试请求

//根据电子文档,查询文档列表
@GetMapping("/edocEntriesPage")
public RequestResult<?> edocEntriesPage(@RequestParam(value = "summary",required = false) String summary,
                                        @RequestParam(value = "pageNo",defaultValue = "1") Integer pageNo,
                                        @RequestParam(value = "pageSize",defaultValue = "3") Integer pageSize){

    if(StringUtils.isBlank(summary)){
        return ResultBuildUtil.fail();
    }

    //调用业务接口,获取文档列表,进行统一返回
    //使用结果构建工具,返回成功的结果
    return ResultBuildUtil.success(edocEntrieService.getEdocEntriesBySummary(summary,pageNo,pageSize));
    
}

测试结果:

2.5 commons-lang3 生成6位随机数

2.5.1 依赖

<!-- commons-lang3 start -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.7</version>
</dependency>
<!-- commons-lang3 end -->

2.5.2 代码

String code = RandomStringUtils.randomNumeric(6);

2.6 Pattern.matches()正则匹配

import java.util.regex.Pattern;

//举例:
if(!Pattern.matches("1[3,5,7,8,9]\\d{9}",userTel)){
    //不匹配的情况
    log.warn("****** 手机号:{},格式非法 ******",userTel);
}


3、统一异常处理

3.1 EdocExceptionEnum 自定义异常枚举

//自定义异常枚举
public enum EdocExceptionEnum {

    /**
     * 参数为空
     */
    EDOC_REQUEST_PARAM_EMPTY("201", "参数为空"),

    /**
     * 参数为非法
     */
    EDOC_REQUEST_PARAM_ILLEGAL("202", "参数非法"),

    /**
     * 网络异常
     */
    EDOC_NETWORK_ERROR("301", "网络异常"),

    /**
     * 数据库异常
     */
    EDOC_DATABASE_ERROR("401", "数据库异常"),

    /**
     * 数据库异常
     */
    EDOC_SYSTEM_ERROR("501", "系统异常");

    /**
     * 异常码
     */
    private String errCode;

    /**
     * 异常说明
     */
    private String errMsg;

    /**
     * 提供带有两个参数的构造方法
     */
    EdocExceptionEnum(String errCode, String errMsg){
        this.errCode = errCode;
        this.errMsg = errMsg;
    }

    public String getErrCode() {
        return errCode;
    }

    public String getErrMsg() {
        return errMsg;
    }

}

3.2 EdocException 自定义异常类

public class EdocException extends RuntimeException{

    /*
        异常枚举类型全局私有属性
    */
    private EdocExceptionEnum edocExceptionEnum;

    //继承 RuntimeException  生成所有的构造方法
    public EdocException() {
    }

    public EdocException(String message) {
        super(message);
    }

    public EdocException(String message, Throwable cause) {
        super(message, cause);
    }

    public EdocException(Throwable cause) {
        super(cause);
    }

    public EdocException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }

    //自定义枚举异常构造函数
    public EdocException(EdocExceptionEnum edocExceptionEnum){
        this.edocExceptionEnum = edocExceptionEnum;
    }

    //获取枚举异常属性
    public EdocExceptionEnum getEdocExceptionEnum() {
        return edocExceptionEnum;
    }
}

3.3 EdocExceptionHandler 自定义异常统一处理类

//自定义异常统一处理类
@ControllerAdvice
public class EdocExceptionHandler {

    /**
     * @author : huayu
     * @date   : 19/10/2022
     * @param  : [edocException]
     * @return : requestResoult<?>
     * @description : 系统自定义异常处理,对系统中所有抛出自定义的异常,都会进行统一拦截处理,实现统一返回
     */
    @ExceptionHandler(EdocException.class)  //指定对该自定义异常类 进行处理
    @ResponseBody  //指定返回的数据 为 json类型
    public RequestResult<?> handleEdocException(EdocException edocException){
        //统一返回失败的结果(前提:抛出的必须是带枚举类型的异常)
        return ResultBuildUtil.fail(edocException.getEdocExceptionEnum().getErrCode(),edocException.getEdocExceptionEnum().getErrMsg());

    }

}

3.4 请求测试

@GetMapping("/edocEntriesPage")
public RequestResult<?> edocEntriesPage(@RequestParam(value = "summary",required = false) String summary,
                                        @RequestParam(value = "pageNo",defaultValue = "1") Integer pageNo,
                                        @RequestParam(value = "pageSize",defaultValue = "3") Integer pageSize){

	//判断 summary参数是否为空
    if(StringUtils.isBlank(summary)){
        //抛出自定义异常:使用异常枚举
        throw new EdocException(EdocExceptionEnum.EDOC_REQUEST_PARAM_EMPTY);
    }

    ////抛出自定义异常:使用异常枚举
    try {
        return ResultBuildUtil.success(edocEntrieService.getEdocEntriesBySummary(summary,pageNo,pageSize));
    } catch (Exception e) {
        //e.printStackTrace();
         //抛出自定义异常:使用异常枚举
        throw new EdocException(EdocExceptionEnum.EDOC_DATABASE_ERROR);
    }

}

测试请求参数为空:

测试数据库密码错误:




有关SpringBoot(八) - 统一数据返回,统一分页工具,统一异常处理 (生成随机数,正则校验)的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  4. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  5. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  6. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

    我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

  7. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  8. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  9. ruby-on-rails - Ruby on Rails - 为文本区域和图片生成列 - 2

    我是Rails的新手,所以请原谅简单的问题。我正在为一家公司创建一个网站。那家公司想在网站上展示它的客户。我想让客户自己管理这个。我正在为“客户”生成一个表格,我想要的三列是:公司名称、公司描述和Logo。对于名称,我使用的是name:string但不确定如何在脚本/生成脚手架终端命令中最好地创建描述列(因为我打算将其设置为文本区域)和图片。我怀疑描述(我想成为一个文本区域)应该仍然是描述:字符串,然后以实际形式进行调整。不确定如何处理图片字段。那么……说来话长:我在脚手架命令中输入什么来生成描述和图片列? 最佳答案 对于“文本”数

  10. ruby - 在 Ruby 中重新分配常量时抛出异常? - 2

    我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案

随机推荐