天天看點

開發中個人常用的Hutool工具類

個人公衆号(小程式同名): 遇見0和1

Hexo部落格: http://vogos.cn

文章目錄

    • 前言
    • 1、模拟HTTP請求
    • 2、JSONUtil 序列化
    • 3、BeanUtil Map與javaBean的轉換
    • 4、CaptchaUtil 生成圖形驗證碼
    • 5、UserAgentUtil
    • 6、FileUtil
    • 7、搬磚中...
開發中個人常用的Hutool工具類

前言

官方介紹: Hutool是一個Java工具包,也隻是一個工具包,它幫助我們簡化每一行代碼,減少每一個方法,讓Java語言也可以“甜甜的”。Hutool最初是我項目中“util”包的一個整理,後來慢慢積累并加入更多非業務相關功能,并廣泛學習其它開源項目精髓,經過自己整理修改,最終形成豐富的開源工具集。Hutool是Hu + tool的自造詞,前者緻敬我的“前任公司”,後者為工具之意,諧音“糊塗”,寓意追求“萬事都作糊塗觀,無所謂失,無所謂得”的境界。

個人看法: 網上對它的看法有好有壞,搜尋hutool就能看到如下他的生态,那些不推薦的原因我就不在這介紹了(畢竟本人是一個菜🐔,沒有這種資格)對于我目前的個人能力來說,它還是非常适合我的,開發時懶得自己寫一些工具類或算法加密什麼的,hutool也可以幫我減少 util 包中的大量工具類,這裡隻記錄個人常用到的一些工具類,它的浩瀚可自行去官方開拓,目前記錄時官方最新版本為v5.6.6

Hutool官網:https://www.hutool.cn

官方文檔:https://apidoc.gitee.com/dromara/hutool

開發中個人常用的Hutool工具類

添加Hutool的所有依賴

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.3.3</version>
</dependency>
           

1、模拟HTTP請求

hutool提供了HttpUtil 和 HttpRequest 兩個工具類都可用來模拟發送http請求,這兩個用法大同小異這裡隻拿HttpRequest舉例

示例場景: 在項目開發中Swagger可作為後端接口測試的良方,但在和别人對接,或使用别人提供的接口時常常需要後端自己去模拟請求發送,去校驗接口

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

/**
 * @author 遇見0和1
 * @company lingStudy
 * @create 2021-06-03 17:04
 */
@Slf4j
public class HttpTest {

    /**
     * putOnce:一次性Put 鍵值對,如果key已經存在抛出異常,如果鍵值中有null值,忽略
     * putOpt:在鍵和值都為非空的情況下put到JSONObject中
     */
    @Test
    void postTest(){
        JSONObject jsonObject = JSONUtil.createObj();// 或 JSONObject jsonObject = new JSONObject();
        jsonObject.putOnce("customerTel","17563964456");
        jsonObject.putOnce("remarks","備注1:我是HttpRequest測試請求!");

        HttpResponse response = HttpRequest.post("http://127.0.0.1:9001/caiyun-record/saveRecord")
                //設定請求頭(可任意加)
                .header("Content-Type", "application/json")
                // 添加token
                .header("Authorization","eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJ7E3NjJ9.9vgMKLpftjcXxmvViSyJDnBcXrO6c3bLlatwD83frAs")
                //請求參數
                .body(jsonObject.toString())
                .execute();
        log.info("請求響應結果:{}",response);
        log.info("響應資料:{}",response.body());
    }

    @Test
    void getTest(){
        HttpResponse response = HttpRequest.get("http://127.0.0.1:9001/caiyun-record/login?paramData=I0CZZJYUBP9JixsyeDkhRnIfFgyXP-NaP1DiJ8_AWoY1eEeZN5BwF_HMSfb4wl6oE")
                .execute();
        log.info("get請求傳回:{}",response.body());
    }

}
           

2、JSONUtil 序列化

将一個對象序列化,也是後端開發中常遇到的,阿裡以前挺火的 fastjson

示例場景: 傳回給前端的token中要存對象時可将對象轉為字元串,在攔截器中再将該字元串重新轉為對象,若在登入後存的是該對象到session中,還可以在攔截器中通過判斷session中的值是否為空,來解決後端重新開機後session丢失的問題。

//對象轉字元串
String userInfoStr = JSONUtil.toJsonStr(userInfoDTO);
log.info("對象轉字元串userInfoStr:{}", userInfoStr);

//生成token
String jwtToken = TokenUtil.createJwtToken(userInfoStr);
           
//字元串轉對象
UserInfoDTO userInfo = JSONUtil.toBean(jti, UserInfoDTO.class);
request.getSession().setAttribute("userInfo",userInfo);
log.info("重設session後:{}",request.getSession().getAttribute("userInfo"));
           

3、BeanUtil Map與javaBean的轉換

示例場景: 面對POST或者一些參數較多的GET請求等,懶得建立參數對象,可用Map來接收前端傳遞的參數

@ApiOperation(value = "新增記錄")
@ApiImplicitParams({
         @ApiImplicitParam(paramType = "query", dataType = "String", name = "customerTel", value = "客戶号碼",required = true),
         @ApiImplicitParam(paramType = "query", dataType = "String", name = "remarks", value = "備注")
 })
 @PostMapping("/saveRecord")
 public ResultVo<Object> saveRecord(@ApiIgnore @RequestBody Map<String, Object> param){
     log.info("新增登記記錄 param:{}",param);
     try {
         HecaiyunRecord hecaiyunRecord = new HecaiyunRecord();
         //将map指派給HecaiyunRecord中與map的key對應的字段
         BeanUtil.fillBeanWithMap(param,hecaiyunRecord,false);
         UserInfoDTO userInfo = (UserInfoDTO) request.getSession().getAttribute("userInfo");
         //用userInfo填充與hecaiyunRecord相同的字段
         BeanUtils.copyProperties(userInfo,hecaiyunRecord);
         //添加系統日志
         sysLogService.saveSysLog(userInfo,request,"add","新增登記");

         return recordService.saveRecord(hecaiyunRecord);
     } catch (Exception e) {
         log.error("新增登記記錄失敗");
         e.printStackTrace();
         throw new MyException(StatusEnum.ERROR);
     }
 }
           

反過來:将JavaBean對象轉為Map對象

User user = new User();
user.setAge(3);
user.setName("遇見0和1");
 
Map<String, Object> map = BeanUtil.beanToMap(user);
           

4、CaptchaUtil 生成圖形驗證碼

示例場景: 圖形驗證碼在登入時非常常見,Hutool也用幾種類型的驗證碼,這裡隻舉例個人常用的一種。

@ApiOperation(value = "獲得圖形驗證碼")
@GetMapping("/getCaptcha")
public void getCaptcha(HttpServletResponse response){
    //生成驗證碼圖檔(定義圖形的寬和高,驗證碼的位數,幹擾線的條數)
    //CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 25);
    CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(100, 50, 4, 25);
    //告訴浏覽器輸出内容為jpeg類型的圖檔
    response.setContentType("image/jpeg");
    //禁止浏覽器緩存
    response.setHeader("Pragma","No-cache");
    try {
        ServletOutputStream outputStream = response.getOutputStream();
        //圖形驗證碼寫出到流,也可以寫出到檔案如:circleCaptcha.write(“d:/circle25.jpeg”);
        circleCaptcha.write(outputStream);
        //從圖形驗證碼圖檔中擷取它的字元串驗證碼(擷取字元串驗證碼要在圖形驗證碼wirte寫出後面才行,不然得到的值為null)
        String captcha = circleCaptcha.getCode();
        request.getSession().setAttribute("captcha",captcha);
        log.info("生成的驗證碼:{}",captcha);
        log.info("session id:{}",request.getSession().getId());
        //關閉流
        outputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
        throw new MyException(StatusEnum.ERROR);
    }
}
           

5、UserAgentUtil

示例場景: 系統記錄檔裡常常需要判斷通路的是什麼裝置 UserAgentUtil 可以擷取到服務的浏覽器詳細資訊,也可以判斷通路是不是移動裝置。

//自己實作
public String isDevice(HttpServletRequest request){
    String requestHeader = request.getHeader("user-agent");
    //定義移動端請求的所有可能類型
    String[] deviceArray = {"android", "iphone","ipod","ipad", "windows phone","mqqbrowser"};
    //将字元串轉換為小寫
    requestHeader = requestHeader.toLowerCase();
    for (String device : deviceArray) {
        if (requestHeader.contains(device)){
            return "移動端";
        }
    }
    return "PC端";
}

//使用UserAgentUtil
public String isDeviceHuTool(HttpServletRequest request){
    String requestHeader = request.getHeader("user-agent");
    UserAgent userAgent = UserAgentUtil.parse(requestHeader);
    if (userAgent.isMobile()){
        return "移動端";
    }
    return "PC端";
}
           

通路者的ip位址常常也是需要儲存的一個資料,個人暫時沒找到hutool對這個的支援,友善後面來抄作業,下面放一個搬來的擷取ip的方法

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;

/**
 * @author 遇見0和1
 * @company lingStudy
 * @create 2021-03-30 9:31
 */
@Slf4j
public class IPUtils {

    /**
     * 擷取IP位址
     *
     * 使用Nginx等反向代理軟體, 則不能通過request.getRemoteAddr()擷取IP位址
     * 如果使用了多級反向代理的話,X-Forwarded-For的值并不止一個,而是一串IP位址,X-Forwarded-For中第一個非unknown的有效IP字元串,則為真實IP位址
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = null;
        try {
            ip = request.getHeader("x-forwarded-for");
            if (StrUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (StrUtil.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StrUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StrUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StrUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } catch (Exception e) {
            log.error("IPUtils ERROR:",e);
        }

        //對于通過多個代理的情況,第一個IP為用戶端真實IP,多個IP按照','分割
        if(!StrUtil.isEmpty(ip) && ip.length() > 15) {
			if(ip.indexOf(",") > 0) {
				ip = ip.substring(0, ip.indexOf(","));
			}
		}

        return ip;
    }

}
           

6、FileUtil

示例場景: 檔案上傳下載下傳在項目中也是一個常見并且重要的業務點,Hutool的FileUtil類對着方面也做了很好的支援。

@Value("${upload-file.img-path}")
private String imgPath;

@ApiOperation(value = "上傳圖檔")
@PostMapping(value = "/uploadImg",headers = "content-type=multipart/form-data")
public ResultVo<Object> uploadFile(@ApiParam(value = "file") @RequestParam(value = "file" ,required = false) MultipartFile file){

    if (file == null){
        throw new MyException(StatusEnum.BUSINID);
    }
    if (!FileUtil.exist(imgPath)){
        FileUtil.mkdir(imgPath);
    }
    //String fileName = UUID.randomUUID().toString() + "@" + multipartFile.getOriginalFilename();
    log.info("原檔案名:{}",file.getOriginalFilename());//包括擴充名
    //檔案擴充名
    String suffix = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf(".") + 1);
    String fileName = System.currentTimeMillis() + RandomUtil.randomNumbers(4) + "." +suffix;
    try {
        File file1 = FileUtil.writeBytes(file.getBytes(), imgPath + fileName);
        log.info("file1:{}",file1);
        return ResultVo.success();
    } catch (IOException e) {
        e.printStackTrace();
        throw new MyException(StatusEnum.ERROR);
    }

}
           

7、搬磚中…