开发问题回顾

  • 跨域问题

    1. 问题

      前端VSCode启动时,没有报跨域。发布在docker中只有一个获取轮廓线模板的路由报跨域

    2. 处理过程

      => 对比本地与docker内前端差异下,网络请求的处理不同

      ​ 本地情况下,所有的后端路由IDE自带的服务器进行了代理,于是不存在跨域问题;

      ​ docker内,后端路由直接经过nginx进入到后端服务器,而后端的url与前端url不同,所有存在跨域

      => 确认CORS的filter

      CORS跨域会对非基本的url发送一个OPTION请求,询问后端是否允许,然后再发送请求。我们的处理是增加了CORSFilter,确认允许返回。

      ​ 看代码确实设置了Credentials、Origin、Methods、Headers进行了规定,这也是为什么其他的路由都正常的原因

      => 通过tcpdump抓波查看该路由与其他路由的差异

      ​ 发现在该路由下,存在一个新的header

      => 重新设置了一下Header,问题解决

    3. 处理结果

       @Override
          public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
              HttpServletResponse res = (HttpServletResponse) response;
              String strOrigin = ((HttpServletRequest) request).getHeader("origin");
              String strHeader = ((HttpServletRequest) request).getHeader("Access-Control-Request-Headers");
              String strMethod = ((HttpServletRequest) request).getMethod();
              String strUrl = ((HttpServletRequest) request).getRequestURL().toString();
              log.info("---{}-{}-{}-{}---",strMethod, strUrl, strOrigin, strHeader);
              res.setHeader("Access-Control-Allow-Credentials", "true");
              res.setHeader("Access-Control-Allow-Origin", strOrigin);
              res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
              res.setHeader("Access-Control-Allow-Headers", strHeader);
              if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
                  response.getWriter().println("ok");
                  return;
              }
              chain.doFilter(request, response);
          }
      
  • jar包内getFile问题

    1. 问题

      导出word方案时,从classpath目录下获取模板文件进行渲染,在IDE上直接启动时,没有问题,但打成jar包后,却报失败

    2. 处理过程

      => 确定打包后的classpath下有该文件

      => 通过日志,查看IDE下的变量与Jar包下变量的差异

      => 换一种Resource加载方式来尝试,原来用的ClassPathResource,改用ResouceUtil。结果无效

      => 不再用File方式,而是用Stream方式,问题解决

    3. 原因

      Resouce::getFile()中有对协议的头进行判断,在jar包中的协议不符合该协议,返回FileNotFoundException

    4. 处理结果

      //        ClassPathResource oldDoc = new ClassPathResource("export/simple-plan1.docx");
      //        String filePath = oldDoc.getFile().getPath();
      
      //        File oldFile = ResourceUtils.getFile("classpath:export/simple-plan1.docx");
      //        String filePath = oldFile.getPath();
              // 以上2种get方式,在jar包中都不可用
              InputStream stream = null;
              try {
              // 以下2种get Stream的方式都可用
      //            ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
      //            Resource resource = resolver.getResource("export/simple-plan1.docx");
      //            stream = resource.getInputStream();
      
                  stream = new ClassPathResource("export/simple-plan1.docx").getInputStream();
              } catch (Exception e){
                  e.printStackTrace();
                  throw e;
              }
              XWPFTemplate template = XWPFTemplate.compile(stream, config)
                      .render(datas);
      
    5. 参考

    6. 规范

      尽量避免使用Resouce直接获取file

  • BigDecimal的使用

    1. 问题

      前端小数点取整精度为2位小数,但却只显示1位

    2. 处理过程

      => 将Double修改为BigDecimal,通过setScale设置精度,结果无效

      ​ 这里有个小插曲,BigDecimal::divde函数当除不尽时,需要提供精度,否则会报异常

      => 增加JsonSerializer,在其中保留2位小数,结果无效

      => 通过tcpdump观察,看到后端返回的数据确实是2位小数0.50,但前端接收到的确实0.5

      => 返回String方式来保证

      => 继续JsonSerializer,返回相应的String

      => 制定想要的功能,返回number、返回不同精度的BigDecimal,返回相同精度的BigDecimal

      => 对JsonFormat进行特殊处理,通过parttern与shape来进行不同配置

    3. 处理结果

      public class BigDecimalSerializer extends JsonSerializer<BigDecimal> implements ContextualSerializer {
          protected  DecimalFormat decimalFormat;
          private Boolean originalFormatString = false;
      
          public BigDecimalSerializer() {
          }
          public BigDecimalSerializer(DecimalFormat decimalFormat) {
              this.decimalFormat = decimalFormat;
          }
      
          @Override
          public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
              if(Objects.isNull(value)) {
                  gen.writeNull();
              } else {
                  if(null != decimalFormat) {
                      String strData = decimalFormat.format(value);
                      gen.writeString(strData);
                  }else {
                      if(originalFormatString){
                          String strData = value.toString();
                          gen.writeString(value.toString());
                      } else {
                          gen.writeNumber(value.setScale(2, BigDecimal.ROUND_HALF_UP));
                      }
                  }
              }
          }
      
          @Override
          public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
      
              JsonFormat.Value format = findFormatOverrides(prov, property, handledType());
              if (format == null) {
                  return this;
              }
      
              if (format.hasPattern()) {
                  DecimalFormat decimalFormat = new DecimalFormat(format.getPattern());
                  decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
                  return new BigDecimalSerializer(decimalFormat);
              } else if(format.hasShape() && format.getShape().compareTo(JsonFormat.Shape.STRING)==0){
                  originalFormatString = true;
              }
      
              return this;
          }
      
          protected JsonFormat.Value findFormatOverrides(SerializerProvider provider, BeanProperty prop, Class<?> typeForDefaults)
          {
              if (prop != null) {
                  return prop.findPropertyFormat(provider.getConfig(), typeForDefaults);
              }
              return provider.getDefaultPropertyFormat(typeForDefaults);
          }
      }
      
      

      该Serializer有3种用法:

      • @JsonSerialize(using = BigDecimalSerializer.class), 将format成数字
      • +@JsonFormat(shape = JsonFormat.Shape.STRING), 按BigDecimal本身的scale转换成string
      • +@JsonFormat(pattern = "00.00", shape = JsonFormat.Shape.STRING),统一format成保留2位小数

      如下:

      //    @JsonFormat(pattern = "00.00", shape = JsonFormat.Shape.STRING)
          @JsonFormat(shape = JsonFormat.Shape.STRING)
          @JsonSerialize(using = BigDecimalSerializer.class)
          @ApiModelProperty(value = "数量")
          private BigDecimal value;
      
    4. 参考

    5. 规范

      • BigDecimal的dive必须加精度
      • 有精度要求的小数场景,返回时用JsonSerialize与JsonFormat进行注解

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×