2.常用功能(分页、文件上传下载_swagger工具_验证码实现)

常用功能合集

1、分页功能实现

1.首先layui开启分页

(一般在table.render里面使用,如果不加参数,默认limit=10,page=1)

,limits: [5, 10, 15, 20, 50, 100] //每页条数的选择项。如果 layout 参数开启了 limit,则会出现每页条数的select选择框
,limit: 5 //每页显示的条数。laypage将会借助 count 和 limit 计算出分页数。
,page: true //是否显示分页

其他参数可以参考layui官方文档——内置模块——分页layerpage的介绍

2.pom.xml配置

<!-- pagehelper -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<!-- 注意:spring boot 引入的jar包必须是要pagehelper-spring-boot-starter ,如果单独引入pagehelper的话,会提示错误。 -->

3.application.yml增加pagehelper 配置

#分页框架
pagehelper:
  helper-dialect: mysql
  reasonable: true
  supportMethodsArguments: true

helperDialect : 指定数据库,可以不配置,pagehelper插件会自动检测数据库的类型。

resonable : 分页合理化参数默认false,当该参数设置为true 时,pageNum <= 0 时,默认显示第一页,pageNum 超过 pageSize 时,显示最后一页。

supportMethodsArguments : 分页插件会根据查询方法的参数中,自动根据params 配置的字段中取值,找到合适的值会自动分页。 

4.在控制器中实现分页

@GetMapping("/getProductList")
@ResponseBody
public Response list(@RequestParam int limit, @RequestParam int page, Product product){
    //limit是每页的条数,page是标识第几页
    PageHelper.startPage(page, limit);
    List<Product> list = productService.selectProductList(product);
    PageInfo pageInfo = new PageInfo(list,limit);
    //        response.setStatusCode(1);
    //        response.setStatusMsg("");
    //        response.setCount(pageInfo.getTotal());
    //        response.setDetailList(pageInfo.getList());
    response = getDataTable(pageInfo,"");
    //可以选择用上面的四句,也可以把这几句封装成一个方法直接调用
    return response;
}

分页的核心就一行代码, PageHelper.startPage(page,pageSize); 这个就标识开始分页。加了这个之后pagehelper 插件就会通过其内部的拦截器,将执行的sql语句,转化为分页的sql语句。

注意:使用时PageHelper.startPage(pageNum, pageSize)一定要放在列表查询的方法中,这样在查询时会查出相应的数据量且会查询出总数。

2、文件上传

参考网址

SpringMVC使用MultipartFile上传文件

MultipartFile介绍

MultipartFile是springmvc官方提供的一个比较完善的文件上传组件,MultipartFile是一个组织接口,它的实现类有

  • org.springframework.web.multipart.commons.CommonsMultipartFile
  • org.springframework.mock.web.MockMultipartFile

它在springmvc中的org.springframework.web.multipart这个包内,与org.springframework.web.multipart. commons和org.springframework.web.multipart.support包内的类接口组合使用该。

单文件上传

前端

<form method="post" action="http://localhost:8888/file/upload" enctype="multipart/form-data">
    <input name = "fileName" type = "file"><br>
   <input type = "submit" value = "点击上传">
</form>

后端

@RestController
public class UpFileController {
    @RequestMapping(value = "/file/upload", method = RequestMethod.POST)
    public void fileUpload(@RequestParam("fileName") MultipartFile file) {
        //这部分都是解决文件名和文件夹的路径
        String deposeFilesDir = "E:\\upload\\";
        String fileName = file.getOriginalFilename();
        // 如果是获取的含有路径的文件名,那么截取掉多余的,只剩下文件名和后缀名
        int index = fileName.lastIndexOf("\\");
        fileName = fileName.substring(index + 1);
        String[] fileNameSplitArray = fileName.split("\\.");
        fileName = fileNameSplitArray[0] + (int) (Math.random() * 100000) + "." + fileNameSplitArray[1];
        
        File dest = new File(deposeFilesDir + fileName);
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        try{
            file.transferTo(dest);
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("文件的全路径名字(含路径、后缀)>>>>>>>" + deposeFilesDir + fileName);
    }
}

多文件上传

前端:上传多文件的话,需在表单的input中加入multiple="multiple"。(可一次选择多个文件)

<form method="post" action="http://localhost:9876/file/mulFileUpload" enctype="multipart/form-data">
   <!-- ,那么这些input按钮的name要一样-->
   <input name = "fileName" multiple="multiple" type = "file"><br>
   <!--如果是多个file输入控件,那么这些input按钮的name要一样-->
    <!--
   <input name = "fileName" type = "file"><br>
   <input name = "fileName" type = "file"><br>
   -->
   <input type = "submit" value = "点击上传">
</form>

后端:在单文件上传的基础上,将MultipartFile 换为数组MultipartFile [],循环遍历即可。

@RequestMapping(value = "/file/mulFileUpload", method = RequestMethod.POST)
public void mulFileUpload(@RequestParam("fileName") MultipartFile[] files) {
    //这部分都是解决文件名和文件夹的路径
    String deposeFilesDir = "E:\\upload\\";
	for (MultipartFile file : files) {
        if(null != file){
            String fileName = file.getOriginalFilename();
            // 如果是获取的含有路径的文件名,那么截取掉多余的,只剩下文件名和后缀名
            int index = fileName.lastIndexOf("\\");
            fileName = fileName.substring(index + 1);
            String[] fileNameSplitArray = fileName.split("\\.");
            fileName = fileNameSplitArray[0] + (int) (Math.random() * 100000) + "." + fileNameSplitArray[1];

            File dest = new File(deposeFilesDir + fileName);
            if (!dest.getParentFile().exists()) {
                dest.getParentFile().mkdirs();
            }
            try{
                file.transferTo(dest);
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("文件的全路径名字(含路径、后缀)>>>>>>>" + deposeFilesDir + fileName);
        }
    }
}

3、文件下载

参考网址

柔哥的:http://10.25.106.209:8090/pages/viewpage.action?pageId=17367421

其他大佬的:https://blog.csdn.net/qq_41076797/article/details/116297837

柔哥的:

文件的下载
a. 读取服务器中的文件
b. 获取Response中的字节流
c. 将读取到的文件传入获取到的字节流中
    
@RequestMapping("/downloadByResponse")
       public void downloadByResponse(@RequestParam("accountId") String accountId, HttpServletResponse response) {
           String filename = accountService.getImagePath(accountId);
           if(filename != null) {
               File file;
               InputStream inputStream = null;
               OutputStream outputStream = null;
               byte[] fileByte = null;
               try {
                   file = new File(filename);
                   inputStream = new FileInputStream(file);
                   /**
                   * 获取Response的字节流,并设定文件格式
                   **/
                   response.setContentType("image");
                   outputStream = response.getOutputStream();
                   int len;
                   byte[] bytes = new byte[1024];
                   while ((len = inputStream.read(bytes)) >= 0) {
                       outputStream.write(bytes, 0, len);
                   }
                   outputStream.flush();
               } catch (Exception e) {
                   e.getMessage();
               } finally {
                   try {
                       inputStream.close();
                       outputStream.close();
                   } catch (Exception e) {
                       e.getMessage();
                   }
               }
           }
       }

4、layui的上传照片和查看照片

上传照片:

前端部分去看看layui官方文档的upload部分,这里只给个后端接口的写法,实际原理就是之前说过的文件上传

    @PostMapping("/uploadImages")
    //图片上传测试
    @ResponseBody
    public Response uploadImages(MultipartFile file, String productId){
        String prefix = "E:\\ProList\\online-retailer\\src\\main\\resources\\static\\images\\";
        //首先得到传进来的文件名称(不是ie浏览器的话一般传进来只有文件名而没有路径)
        String filename = file.getOriginalFilename();
        //文件后缀名从.后面一位开始
        String suffix = filename.substring(filename.lastIndexOf('.'));
        //总的文件路径=上级文件夹名称+文件名+后缀名
        filename = prefix + productId + suffix;
        //建立句柄
        File localfile = new File(filename);
        //如果祖辈文件夹不存在,建立上级文件夹和空文件
        if (!localfile.getParentFile().exists()) {
            localfile.getParentFile().mkdirs();
            System.out.println("创建成功!");
        }
        try{
            file.transferTo(localfile);
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("文件的全路径名字(含路径、后缀)>>>>>>>"  + filename);
        response.setSuccessed("sss");
        return response;
    }

查看照片:

5、swagger接口文档

参考资料

实战入门:https://www.cnblogs.com/zhangweizhong/p/13185919.html

官方网站:https://swagger.io/

使用手册:https://gumutianqi1.gitbooks.io/specification-doc/content/tools-doc/spring-boot-swagger2-guide.html

Maven仓库:https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui

6、验证码的实现(这个没做,有时间来看,感谢柔哥儿)

引入依赖:

<dependency>
   <groupId>com.github.whvcse</groupId>
   <artifactId>EasyCaptcha</artifactId>
   <version>1.5.0</version>
</dependency>

将图片与内容分别存在输出流与Session中返回到前端:

public void captcha(HttpServletRequest req,HttpServletResponse res){
        OutputStream outputStream = null;
        try{
            outputStream = res.getOutputStream();
            SpecCaptcha specCaptcha = new SpecCaptcha(130,48,4);
            specCaptcha.setCharType(Captcha.TYPE_DEFAULT);
            String code = specCaptcha.text();
            req.getSession().setAttribute("captcha",specCaptcha.text().toLowerCase());
            specCaptcha.out(outputStream);
            outputStream.flush();
        } catch (Exception e){
            e.getMessage();
        } finally {
            try {
                outputStream.close();
            } catch (Exception e){
                e.getMessage();
            }
        }
    }

接收前端验证码,与Session中存储的字符做对比:

public AccountIdResponse createAccount(@RequestBody @Validated CreateAccountRequest createAccountRequest, HttpServletRequest req) {
       AccountIdResponse accountIdResponse = new AccountIdResponse();
       String  captcha= (String)req.getSession().getAttribute("captcha");
       if(captcha.equals( createAccountRequest.getCaptcha().toLowerCase() )){
           /**
           * do something
           **/
       } else{
           accountIdResponse.setStatusCode(0);
           accountIdResponse.setStatusMsg("验证码错误!");
 
       }
       return accountIdResponse;
   }

7、其他(下面都是转载,防止内网打不开)

常用注解:

http://10.25.106.209:8090/pages/viewpage.action?pageId=17367449

  • Spring Boot
    @Mapper 映射文件 Spring不主动扫描 需要在main函数中加入@MapperScan(basePackages = "com.baosight.mytutorial.persist.mapper")
    @Service 提供服务 当Service由接口构成时加在具体实现类之前
    @Controller @RestController 控制器
  • swagger
    @Api(tags={接口用途}) ->放在Controller前 用于说明控制器的作用
    @ApiOperation(value = "具体操作",notes = "返回内容说明") -> 放在Response或Request前 用于说明请求(响应)的具体功能
    @ApiModelProperty(value = "",required = "") -> 放在Response或Request的属性前 说明属性作用

  • Lombok
    @Data 自动生成getter和setter,toString等函数

  • 其他
    @NotEmpty 放在Request的String属性前 用于判断非空
    @Controller 控制器 一般在请求页面的类中使用
    @RestController 可以省略@ResponseBody (会自动将回复内容转化为json格式)
    @RequestBody 请求体注解,一般用于请求页面(后边的变量为请求体)
    @Validated 与not empty或?共同作用 判断是否有效
    @Autowired 自动装配

    @ControllerAdvice
    结合@ExceptionHandler用于全局异常的处理。用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的;
    结合@InitBinder,用于request中自定义参数解析方式进行注册,从而达到自定义指定格式参数的目的;
    结合方法型注解@ModelAttribute,表示其标注的方法将会在目标Controller方法执行之前执行。

  • 未使用的注解
    @Bean
    @Componnent 与@Service用途相似
    @Qualifier

错误处理

http://10.25.106.209:8090/pages/viewpage.action?pageId=17367451

  • mybatis将获得的数据注入到PO中

直接注入会因为下划线等原因造成Spring适应不良,因此采用ResultMap的方式将PO中的属性与数据库中的字段进行映射

  • 将String传入到mybatis中

    1. 在Mapper接口的参数前加注解@Param("变量名")
    2. 在MyBatis文件中按照正常方式传值
  • 空指针错误
    对null对象使用圆点运算符(".")会造成空指针异常,对可能取出空值的查询,需要在调用其方法前判断一下是否非空。
    若判断是否非空的是单独的对象,可以使用StringUtils.isEmpty(Bean)进行判断;
    若判断的对象是ArrayList,则使用list.size()>0 进行判断。

  • public
    在接口中不需要定义访问权限,改为在实现中定义。

  • 代码规约

    1. 获取参数时使用@RequestBody和@RequestParam,不使用其他方式(例如,@PathVariable在传入多参数时,可能造成混乱)
    2. 多行注释一般用于在函数外部进行注释说明
      单行注释一般用于函数间内容的说明
      在文件开头需要对作者等信息进行注释,方便寻找代码责任人
      注释一般单独起一行书写,不能在行尾直接书写
      注释和没用的代码在项目完成后删除,以提高项目的可读性
  • 其他
    可以看一下工具类的使用,比如对象
    不能用==来比较,只能equals或者compareTo
    比如toString有时候也要注意可能会有坑,比如给你返回一个“null”,就可以用ObjectUtils.getDisplayString
    还有,和null做比较的时候,或者和一个常量做比较的时候,要把自己的变量放在比较表达式的后面,不然可能空指针异常

*** 注意事项**

  • 接口设计
    解耦合的过程中通常将单个查询和多个查询分开实现(个人认为从Service层开始分离即可)
  • 事务管理
    注意事务的原子性,进行事务管理的部分如果出错则全部回滚。当进行可以拆分成互不影响的小动作的方法时,可以拆分开对每个小方法单独进行事务管理。
  • 异常处理
    异常处理除了try/catch块外,还可以duck给上一级函数进行处理,但是需要在函数定义时声明可能会抛出的异常(throws Exception),否则运行时产生的异常不会抛出,会直接导致程序报错。
posted @ 2021-08-31 16:36  Lexie——01  阅读(435)  评论(0编辑  收藏  举报