StringUtils.isEmpty() 过期了,用什么替换?

本文通过一个具体的Java示例代码片段介绍了StringUtils类中的hasText()方法如何判断字符串是否为null、空或仅包含空白字符,并展示了其返回值的具体含义。
@Test
    public void test01(){
        String s1 = null;  // null对象
        String s2 = "";  // 空串
        String s3 = " "; // 带空格
        System.out.println("s1:"+ StringUtils.hasText(s1));
        System.out.println("s2:"+ StringUtils.hasText(s2));
        System.out.println("s3:"+ StringUtils.hasText(s3));
    }
    /*
    控制台输出:
		s1:false
		s2:false
		s3:false
*/

用 StringUtils.hasText() 代替
package com.hw.camunda.config.filter; import com.alibaba.fastjson2.JSONObject; import com.hw.camunda.config.SecurityProperties; import com.hw.camunda.constant.RedisConstant; import com.hw.camunda.entity.LoginUserInfo; import com.hw.camunda.exception.BaseException; import com.hw.camunda.exception.ErrorMsg; import com.hw.camunda.service.impl.CustomUserDetailsService; import com.hw.camunda.utils.ContextHolder; import com.hw.camunda.utils.JwtUtil; import com.hw.camunda.utils.RedisUtil; import io.jsonwebtoken.Claims; import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; import org.springframework.util.AntPathMatcher; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; @Order(1) @Component public class TokenFilter extends OncePerRequestFilter { private final SecurityProperties securityProperties; private final CustomUserDetailsService userDetailsService; private final RedisUtil redisUtil; @Autowired public TokenFilter(RedisUtil redisUtil,SecurityProperties securityProperties, CustomUserDetailsService userDetailsService) { this.securityProperties = securityProperties; this.userDetailsService = userDetailsService; this.redisUtil = redisUtil; } // 允许的过期后刷新时间(分钟) private static final int ALLOW_EXPIRED_MINUTES = 10; private static final AntPathMatcher pathMatcher = new AntPathMatcher(); @Override public boolean shouldNotFilter(HttpServletRequest request) { String uri = request.getRequestURI(); List<String> permitUrls = securityProperties.getPermitUrls(); if (!permitUrls.isEmpty() && permitUrls.contains(uri)) { return true; } List<String> pattenUrls = securityProperties.getPattenUrls(); if (!pattenUrls.isEmpty()) { for (String pattenUrl : pattenUrls) { if (pathMatcher.match(pattenUrl, uri)) { return true; } } } return false; } @Override public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { chain.doFilter(request, response); return; } // 从请求头中获取token String token = ContextHolder.getToken(); if (token == null || token.isEmpty()) { throw new BaseException(ErrorMsg.JWT_TOKEN_INVALID); } //token存在直接放行 if (!redisUtil.hasKey(RedisConstant.TOKEN_FILTER_KEY + token)) { try { Claims claims = JwtUtil.getClaims(token); LoginUserInfo userInfo = claims.get("data", LoginUserInfo.class); Date expiration = claims.getExpiration(); Date now = new Date(); long diffInMillis = expiration.getTime() - now.getTime(); if (diffInMillis <= 0) {//token 过期了 // 尝试刷新令牌 try { token = JwtUtil.refreshToken(token, RedisConstant.TOKEN_FILTER_KEY_REFRESH_TIME); Claims newClaims = JwtUtil.getClaims(token); userInfo.setToken(token); newClaims.put("data", userInfo); redisUtil.set(RedisConstant.TOKEN_FILTER_KEY + token, JSONObject.toJSONString(newClaims),RedisConstant.TOKEN_FILTER_KEY_TIME, TimeUnit.MINUTES); // 将新令牌设置到响应头,客户端需要保存并替换旧令牌 response.setHeader("New-Access-Token", token); } catch (BaseException ex) { // 刷新失败,抛出异常(可能是过期时间超过10分钟或无效token) throw ex; } }else{ throw new BaseException(ErrorMsg.LOGIN_TOKEN_CANCEL); //redisUtil.set(RedisConstant.TOKEN_FILTER_KEY + token, JSONObject.toJSONString(claims),diffInMillis, TimeUnit.MILLISECONDS); } } catch (BaseException e) { throw e; } } //最好保存到redis省去解密操作 UserDetails userDetails = userDetailsService.loadUserByUsername(token); UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authenticationToken); chain.doFilter(request, response); } } package com.hw.camunda.config; import com.alibaba.fastjson2.JSONObject; import com.hw.camunda.config.filter.TokenFilter; import com.hw.camunda.exception.ErrorMsg; import com.hw.camunda.service.impl.CustomUserDetailsService; import com.hw.camunda.utils.JsonResult; import jakarta.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.AccessDecisionVoter; import org.springframework.security.access.vote.AffirmativeBased; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import java.util.List; @Configuration @EnableWebSecurity @EnableMethodSecurity // 启用方法级注解鉴权 public class SecurityConfig { private final CustomUserDetailsService userDetailsService; private final SecurityProperties securityProperties; private final TokenFilter tokenFilter; @Autowired public SecurityConfig(TokenFilter tokenFilter,SecurityProperties securityProperties,CustomUserDetailsService userDetailsService) { this.securityProperties = securityProperties; this.userDetailsService = userDetailsService; this.tokenFilter = tokenFilter; } /** * 安全过滤链配置 - 清晰定义拦截规则 * 优先级:从上到下匹配规则 */ @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(AbstractHttpConfigurer::disable) .addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class) .authorizeHttpRequests(auth -> { auth.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll(); // 关键放行 if (!securityProperties.getPermitUrls().isEmpty()) { for (String permitUrl : securityProperties.getPermitUrls()) { auth.requestMatchers(permitUrl).permitAll(); } } if (!securityProperties.getPattenUrls().isEmpty()) { for (String pattenUrl : securityProperties.getPattenUrls()) { auth.requestMatchers(pattenUrl).permitAll(); } } auth.requestMatchers("/**").hasAuthority("ROLE_SUPER_ADMIN"); auth.anyRequest().authenticated(); }) .exceptionHandling(e -> e.authenticationEntryPoint((req, res, ex) -> { // 将异常转换为JSON响应 res.setStatus(HttpStatus.UNAUTHORIZED.value()); res.setContentType("application/json"); res.setCharacterEncoding("UTF-8"); res.getWriter().write(JSONObject.toJSONString(JsonResult.error(ErrorMsg.JWT_TOKEN_INVALID))); })); return http.build(); } } package com.hw.camunda.controller; import com.hw.camunda.constant.RedisConstant; import com.hw.camunda.entity.ReqPage; import com.hw.camunda.utils.JsonResult; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.hw.camunda.entity.SysMenu; import com.hw.camunda.service.SysMenuService; import com.hw.camunda.utils.RedisUtil; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import org.springframework.util.StringUtils; import com.hw.camunda.exception.ErrorMsg; import jakarta.annotation.Resource; import java.util.Arrays; /** * 菜单权限表(SysMenu)表控制层 * * @author nie * @since 2025-08-21 09:14:28 */ @RestController @RequestMapping("/api/sysMenu") public class SysMenuController { /** * 服务对象 */ @Resource private SysMenuService sysMenuService; @Resource private RedisUtil redisUtil; /** * 分页查询所有数据 */ /*@PostMapping("/page") public JsonResult<?> selectPage(@RequestBody ReqPage<SysMenu> req) { if (req.getPageNo() <= 0 || req.getPageSize() <= 0) { return JsonResult.error(ErrorMsg.PARAM_ERROR); } Page<SysMenu> page = new Page<>(req.getPageNo(), req.getPageSize()); return JsonResult.success(this.sysMenuService.page(page, new QueryWrapper<>(req.getData()))); }*/ @PostMapping("/getTree") @PreAuthorize("hasAuthority('system:menu:list')") public JsonResult<?> getTree() { return JsonResult.success(this.sysMenuService.getTree()); } /** * 查询列表数据 */ @PostMapping("/list") @PreAuthorize("hasRole('ROLE_super') or hasRole('ROLE_admin')") public JsonResult<?> selectAll(@RequestBody SysMenu sysMenu) { return JsonResult.success(this.sysMenuService.list( new QueryWrapper<>(sysMenu))); } /** * 通过主键查询单条数据 */ @GetMapping("/detail") public JsonResult<?> selectOne(String id) { return JsonResult.success(this.sysMenuService.getById(id)); } /** * 新增数据 */ @PostMapping("/save") public JsonResult<?> insert(@RequestBody SysMenu sysMenu) { this.sysMenuService.save(sysMenu); redisUtil.delete(RedisConstant.MENU_ALL_KEY); return JsonResult.success(); } /** * 修改数据 */ @PostMapping("/update") public JsonResult<?> update(@RequestBody SysMenu sysMenu) { redisUtil.delete(RedisConstant.MENU_ALL_KEY); this.sysMenuService.updateById(sysMenu); return JsonResult.success(); } /** * 删除数据 */ @PostMapping("/delete") public JsonResult<?> delete(String ids) { if (!StringUtils.hasLength(ids)) { return JsonResult.error(ErrorMsg.PARAM_ERROR); } this.sysMenuService.removeByIds(Arrays.asList(ids.split(","))); redisUtil.delete(RedisConstant.MENU_ALL_KEY); return JsonResult.success(); } } 我需要所有的接口SUPER_ADMIN都可以直接访问
08-22
package com.fugui.star.business.business.service; import cn.hutool.core.bean.BeanUtil; import cn.idev.excel.util.StringUtils; import com.baomidou.mybatisplus.core.metadata.IPage; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fugui.cloud.common.entity.page.PageR; import com.fugui.cloud.common.result.R; import com.fugui.star.business.business.query.DwScanOrderPayRecordQuery; import com.fugui.star.business.business.vo.DwScanOrderPayRecordVO; import com.fugui.star.business.business.vo.PaymentPlatformStatVO; import com.fugui.star.persist.fg_business.dao.DwScanOrderPayRecordDAO; import com.fugui.star.persist.fg_business.dto.DwScanOrderPayRecordDTO; import com.fugui.star.persist.fg_business.dto.PaymentPlatformStatDTO; import com.fugui.star.persist.fg_business.search.DwScanOrderPayRecordSearch; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.time.*; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Slf4j @Service public class DwScanOrderPayRecordService { @Resource private DwScanOrderPayRecordDAO dwScanOrderPayRecordDAO; @Resource private RedisTemplate<String, String> redisTemplate; private final ObjectMapper privateMapper = createPrivateMapper(); private ObjectMapper createPrivateMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); return mapper; } public R<PageR<DwScanOrderPayRecordVO>> page(DwScanOrderPayRecordQuery query) { DwScanOrderPayRecordSearch search = BeanUtil.copyProperties(query, DwScanOrderPayRecordSearch.class); IPage<DwScanOrderPayRecordDTO> page = dwScanOrderPayRecordDAO.page(search); PageR<DwScanOrderPayRecordVO> pageR = PageR.get(page).convert(dto -> { DwScanOrderPayRecordVO RecordVo = BeanUtil.copyProperties(dto, DwScanOrderPayRecordVO.class); return RecordVo; }); return R.success(pageR); } public R<List<PaymentPlatformStatVO>> stats(DwScanOrderPayRecordQuery query){ DwScanOrderPayRecordSearch Search = BeanUtil.copyProperties(query, DwScanOrderPayRecordSearch.class); ZonedDateTime now = ZonedDateTime.now(); if (Search.getEndCreateTime() == null) { Search.setEndCreateTime(Date.from(now.toInstant())); } if (Search.getBeginCreateTime() == null) { // 修复:使用ZonedDateTime进行月份运算 ZonedDateTime sixMonthsAgo = now.minusMonths(6); Search.setBeginCreateTime(Date.from(sixMonthsAgo.toInstant())); } // 转换为 LocalDateTime ZonedDateTime startZdt = Search.getBeginCreateTime().toInstant() .atZone(ZoneId.systemDefault()); ZonedDateTime endZdt = Search.getEndCreateTime().toInstant() .atZone(ZoneId.systemDefault()); List<YearMonth> requiredMonths = generateMonthRange(startZdt, endZdt); List<PaymentPlatformStatVO> resultList = new ArrayList<>(); Set<YearMonth> missingMonths = new HashSet<>(); //尝试从缓存获取已有月份数据 for (YearMonth month : requiredMonths) { String cacheKey = "paymentStats:" + month; try { String cachedData = redisTemplate.opsForValue().get(cacheKey); if (StringUtils.isNotBlank(cachedData)) { PaymentPlatformStatVO cachedVO = privateMapper.readValue(cachedData, PaymentPlatformStatVO.class); resultList.add(cachedVO); } else { missingMonths.add(month); } } catch (Exception e) { log.error("缓存读取失败 [月份: {}]", month, e); missingMonths.add(month); } } //如果所有月份都有缓存,直接返回结果 if (missingMonths.isEmpty()) { // 按年月倒序排序 resultList.sort(Comparator.comparing(PaymentPlatformStatVO::getStatYear) .thenComparing(PaymentPlatformStatVO::getStatMonth) .reversed()); return R.success(resultList); } try { //查询缺失月份的数据 List<PaymentPlatformStatDTO> dtoList; if (missingMonths.size() == requiredMonths.size()) { // 全部缺失时查询整个时间范围 dtoList = dwScanOrderPayRecordDAO.stats(Search); } else { // 只查询缺失月份 dtoList = new ArrayList<>(); for (YearMonth month : missingMonths) { // 构建单月查询条件 DwScanOrderPayRecordSearch monthQuery = new DwScanOrderPayRecordSearch(); BeanUtil.copyProperties(Search, monthQuery); // 使用 TemporalAdjusters 精确设置月首/月末时间 LocalDateTime monthStart = month.atDay(1).atStartOfDay(); LocalDateTime monthEnd = month.atEndOfMonth().atTime(23, 59, 59); monthQuery.setBeginCreateTime(Date.from(monthStart.atZone(ZoneId.systemDefault()).toInstant())); monthQuery.setEndCreateTime(Date.from(monthEnd.atZone(ZoneId.systemDefault()).toInstant())); dtoList.addAll(dwScanOrderPayRecordDAO.stats(monthQuery)); } } //处理查询结果并缓存 Map<String, PaymentPlatformStatVO> monthMap = new HashMap<>(); for (PaymentPlatformStatDTO dto : dtoList) { LocalDate localDate = dto.getStatDay().toInstant() .atZone(ZoneId.systemDefault()) .toLocalDate(); String monthKey = localDate.getYear() + "-" + String.format("%02d", localDate.getMonthValue()); PaymentPlatformStatVO monthVo = monthMap.computeIfAbsent(monthKey, k -> { PaymentPlatformStatVO vo = new PaymentPlatformStatVO(); vo.setStatYear(localDate.getYear()); vo.setStatMonth(localDate.getMonthValue()); vo.setMonthAlipayCount(0L); vo.setMonthWechatPayCount(0L); vo.setOtherPayCount(0L); return vo; }); monthVo.setMonthAlipayCount(monthVo.getMonthAlipayCount() + dto.getAlipayCount()); monthVo.setMonthWechatPayCount(monthVo.getMonthWechatPayCount() + dto.getWechatPayCount()); monthVo.setOtherPayCount(monthVo.getOtherPayCount() + dto.getOtherPayCount()); } //缓存缺失月份数据并添加到结果集 for (PaymentPlatformStatVO vo : monthMap.values()) { YearMonth month = YearMonth.of(vo.getStatYear(), vo.getStatMonth()); if (missingMonths.contains(month)) { vo.setMonthTotalOrderCount(vo.getMonthAlipayCount() + vo.getMonthWechatPayCount() + vo.getOtherPayCount()); try { String cacheKey = "paymentStats:" + month; String jsonData = privateMapper.writeValueAsString(vo); if (month.equals(YearMonth.from(now))) { // 当月缓存:设置为次日凌晨过期 ZonedDateTime nextDayStart = now.toLocalDate().plusDays(1).atStartOfDay(ZoneId.systemDefault()); Duration duration = Duration.between(now, nextDayStart); redisTemplate.opsForValue().set(cacheKey, jsonData, duration.getSeconds(), TimeUnit.SECONDS); } else { // 非当月:设置为永久缓存 redisTemplate.opsForValue().set(cacheKey, jsonData); } } catch (Exception e) { log.error("缓存写入失败 [月份: {}]", month, e); } resultList.add(vo); } } //合并缓存数据和新增数据后排序 resultList.sort(Comparator.comparing(PaymentPlatformStatVO::getStatYear) .thenComparing(PaymentPlatformStatVO::getStatMonth) .reversed()); return R.success(resultList); } catch (Exception e) { return R.failed("按月统计失败:" + e.getMessage()); } } private List<YearMonth> generateMonthRange(ZonedDateTime start, ZonedDateTime end) { List<YearMonth> months = new ArrayList<>(); YearMonth startMonth = YearMonth.from(start); // 自动提取年月 YearMonth endMonth = YearMonth.from(end); for (YearMonth month = startMonth; !month.isAfter(endMonth); month = month.plusMonths(1)) { months.add(month); } return months; } public R<List<PaymentPlatformStatVO>> Stats(DwScanOrderPayRecordQuery query) { ZonedDateTime now = ZonedDateTime.now(); // 处理日期范围 if (query.getBeginCreateTime() == null) { ZonedDateTime sevenDaysAgo = now.minusDays(7); query.setBeginCreateTime(Date.from(sevenDaysAgo.toInstant())); } if (query.getEndCreateTime() == null) { query.setEndCreateTime(Date.from(now.toInstant())); } LocalDate startDate = query.getBeginCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); LocalDate endDate = query.getEndCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); List<LocalDate> requiredDates = startDate.datesUntil(endDate.plusDays(1)) .collect(Collectors.toList()); //创建默认结果集 Map<LocalDate, PaymentPlatformStatVO> resultMap = new HashMap<>(); for (LocalDate date : requiredDates) { // 创建默认VO,所有值为0 PaymentPlatformStatVO defaultVo = new PaymentPlatformStatVO(); defaultVo.setStatDay(Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant())); defaultVo.setOtherPayCount(0L); defaultVo.setAlipayCount(0L); defaultVo.setWechatPayCount(0L); defaultVo.setTotalOrderCount(0L); resultMap.put(date, defaultVo); } List<PaymentPlatformStatVO> resultList = new ArrayList<>(); List<LocalDate> missingDates = new ArrayList<>(); Map<String, String> cacheKeys = new HashMap<>(); for (LocalDate date : requiredDates) { if (!date.isBefore(now.toLocalDate())) { missingDates.add(date); continue; } String dateKey = date.format(DateTimeFormatter.ISO_LOCAL_DATE); String cacheKey = "DailyOrderStats::" + dateKey; cacheKeys.put(dateKey, cacheKey); try { String cachedData = redisTemplate.opsForValue().get(cacheKey); if (StringUtils.isNotBlank(cachedData)) { PaymentPlatformStatVO vo = privateMapper.readValue(cachedData, PaymentPlatformStatVO.class); // 用缓存数据替换默认值 resultMap.put(date, vo); } else { missingDates.add(date); } } catch (Exception e) { log.error("缓存读取失败 [日期: {}]", date, e); missingDates.add(date); } } DwScanOrderPayRecordSearch Search = BeanUtil.copyProperties(query, DwScanOrderPayRecordSearch.class); try { // 处理缺失日期 if (!missingDates.isEmpty()) { // 获取最小和最大缺失日期 LocalDate minDate = missingDates.stream().min(LocalDate::compareTo).orElse(startDate); LocalDate maxDate = missingDates.stream().max(LocalDate::compareTo).orElse(endDate); // 设置查询时间范围 Search.setBeginCreateTime(Date.from(minDate.atStartOfDay(ZoneId.systemDefault()).toInstant())); Search.setEndCreateTime(Date.from(maxDate.atTime(23, 59, 59).atZone(ZoneId.systemDefault()).toInstant())); // 执行数据库查询 List<PaymentPlatformStatDTO> dtoList = dwScanOrderPayRecordDAO.stats(Search); for (PaymentPlatformStatDTO dto : dtoList) { LocalDate date = dto.getStatDay().toInstant() .atZone(ZoneId.systemDefault()) .toLocalDate(); if (!missingDates.contains(date)) continue; PaymentPlatformStatVO vo = new PaymentPlatformStatVO(); vo.setStatDay(dto.getStatDay()); vo.setAlipayCount(dto.getAlipayCount()); vo.setWechatPayCount(dto.getWechatPayCount()); vo.setOtherPayCount(dto.getOtherPayCount()); vo.setTotalOrderCount( dto.getAlipayCount() + dto.getWechatPayCount() + dto.getOtherPayCount() ); resultMap.put(date, vo); //缓存时跳过当日及之后日期 if (date.isBefore(now.toLocalDate())) { try { String dateKey = date.format(DateTimeFormatter.ISO_LOCAL_DATE); String cacheKey = cacheKeys.get(dateKey); String jsonData = privateMapper.writeValueAsString(vo); // 设置固定缓存时间(例如30天) redisTemplate.opsForValue().set( cacheKey, jsonData ); } catch (Exception e) { log.error("缓存写入失败 [日期: {}]", date, e); } } } } // 准备最终结果 resultList = new ArrayList<>(resultMap.values()); resultList.sort(Comparator.comparing( vo -> { // 如果statDay为空,则使用最小可能日期 return vo.getStatDay() != null ? vo.getStatDay().toInstant() : Instant.MIN; }, Comparator.nullsLast(Comparator.naturalOrder()) )); return R.success(resultList); } catch (Exception e) { log.error("订单统计异常", e); // 发生异常时返回默认结果 resultList = new ArrayList<>(resultMap.values()); resultList.sort(Comparator.comparing( vo -> { // 如果statDay为空,则使用最小可能日期 return vo.getStatDay() != null ? vo.getStatDay().toInstant() : Instant.MIN; }, Comparator.nullsLast(Comparator.naturalOrder()) )); return R.success(resultList); } } } 如何评价上述接口的service层
08-14
public AjaxResult uploadImage(MultipartFile file) { // ====================== // 1. 增强文件验证逻辑 // ====================== if (file == null || file.isEmpty()) { log.warn("上传失败:空文件请求"); return AjaxResult.error("请选择有效图片文件"); } String originalFilename = StringUtils.defaultIfBlank(file.getOriginalFilename(), "未命名"); if (!isValidImageExtension(originalFilename)) { log.warn("上传失败:不支持的文件类型 - {}", originalFilename); return AjaxResult.error("仅支持 JPG/PNG/GIF 格式"); } // 微信文件大小限制:2MB ($2 \times 1024^2$ 字节) final long MAX_SIZE = 2 * 1024 * 1024; if (file.getSize() > MAX_SIZE) { log.warn("文件过大:{} > {} bytes", file.getSize(), MAX_SIZE); return AjaxResult.error("图片大小不得超过 2MB"); } // ====================== // 2. 获取 AccessToken(复用已有方法) // ====================== String accessToken; try { accessToken = getAccessToken(); // 复用已有方法 if (accessToken == null || accessToken.isEmpty()) { log.error("微信令牌获取失败"); return AjaxResult.error("系统认证异常:ERR_TOK_01"); } } catch (IOException e) { log.error("AccessToken获取失败", e); return AjaxResult.error("系统繁忙,请稍后重试"); } // ====================== // 3. 构建上传请求(使用连接池) // ====================== String uploadUrl = String.format("https://api.weixin.qq.com/cgi-bin/media/upload?access_token=%s&type=image", accessToken); // 复用HTTP连接池(降低资源开销) try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionTimeToLive(5, TimeUnit.SECONDS).build()) { HttpPost httpPost = new HttpPost(uploadUrl); MultipartEntityBuilder builder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.BROWSER_COMPATIBLE).setCharset(StandardCharsets.UTF_8); // 获取文件输入流,避免一次性读入内存 try (InputStream inputStream = file.getInputStream()) { ContentType contentType = ContentType.create(getMimeType(originalFilename)); builder.addBinaryBody("media", inputStream, contentType, originalFilename); } catch (IOException e) { log.error("文件流读取异常", e); return AjaxResult.error("文件处理失败"); } httpPost.setEntity(builder.build()); // ====================== // 4. 执行上传并解析响应 // ====================== try (CloseableHttpResponse response = httpClient.execute(httpPost)) { int statusCode = response.getStatusLine().getStatusCode(); HttpEntity entity = response.getEntity(); String responseBody = entity != null ? EntityUtils.toString(entity, StandardCharsets.UTF_8) : "{}"; // 微信API错误处理(HTTP 200但业务错误) if (statusCode != HttpStatus.SC_OK) { log.error("微信接口异常[{}]:{}", statusCode, responseBody); return AjaxResult.error("微信服务不可用"); } JSONObject json = JSON.parseObject(responseBody); if (json.getIntValue("errcode") != 0) { String errMsg = json.getString("errmsg"); log.error("微信上传失败[{}]:{}", json.getIntValue("errcode"), errMsg); return AjaxResult.error("微信返回错误:" + errMsg); } // ====================== // 5. 触发异步下载任务 // ====================== String mediaId = json.getString("media_id"); WeChatDTO dto = new WeChatDTO(); dto.setMedia_id(mediaId); dto.setBianhao(UUID.randomUUID().toString()); dto.setFilename(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())); kafkaService.sendMessage("file-download-task", JSON.toJSONString(dto)); return AjaxResult.success(Map.of("mediaId", mediaId, "type", json.getString("type"), "fileName", originalFilename, "msg", "上传成功,后台正在异步下载")); } } catch (Exception e) { log.error("上传流程异常", e); return AjaxResult.error("系统处理失败:" + e.getClass().getSimpleName()); } } /** * 校验图片扩展名(防伪造MIME类型) * @param filename 文件名 * @return 是否合法 */ private boolean isValidImageExtension(String filename) { if (filename == null) { return false; } String lowerFilename = filename.toLowerCase(); return lowerFilename.endsWith(".jpg") || lowerFilename.endsWith(".jpeg") || lowerFilename.endsWith(".png") || lowerFilename.endsWith(".gif"); } private String getMimeType(String filename) { if (filename == null) return "image/jpeg"; String lower = filename.toLowerCase(); if (lower.endsWith(".png")) return "image/png"; if (lower.endsWith(".gif")) return "image/gif"; return "image/jpeg"; // 默认 }这是你的意思吗
最新发布
09-02
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值