soft_xiang

soft_xiang 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

soft_xiang 赞了回答 · 11月26日

linux环境使用docker部署php环境报错File not found.

已找到解决方案:
修改nginx配置即可
fastcgi_param SCRIPT_FILENAME /www$fastcgi_script_name;

关注 3 回答 3

soft_xiang 发布了文章 · 9月3日

常用正则表达式

主要记录一些正则表达式

匹配指定格式中的中文

image.png

var reg = /(?<=prompt:.*)([\u4e00-\u9fa5]+)(?=.*,)/g //断言用法
"prompt:  '请选择商品编码'  ,searcher:function(){xxx[商品编码]}".match(reg); //匹配到 请选择商品编码

匹配特殊[]

var patt = /(?<=\[).+?(?=\])|(?<=\().+?(?=\))/g;
"操作失败,单号[0001]中(0002)不存在".replace(patt,'8888');
// 结果 操作失败,单号[8888]中(8888)不存在
查看原文

赞 0 收藏 0 评论 0

soft_xiang 发布了文章 · 7月21日

jasperreport 6.0 导出 excel 异常

做一个jasperreport6 导出excel的功能时,出现一个问题,在测试环境(centos7)正常,发到客户环境(centos7)后异常,最开始为:

Handler  processing  failed;  nested  exception  is  java.lang.NoClassDefFoundError:  Could  not  initialize  class  net.sf.jasperreports.engine.util.JRStyledTextParser

查看tomcat9中项目中的lib下有重复版本jar包,处理以后重启,报

org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11GraphicsEnvironment
    
java.lang.InternalError: Cant connect to X11 window server using 'localhost:10.0' as the value of the DISPLAY variable.
at sun.awt.X11GraphicsEnvironment.initDisplay(Native Method)

最终解决办法为:
在tomcat启动脚本 start.sh 中加入:
export CATALINA\_OPTS="-Djava.awt.headless=true"
image.png
参见:

https://blog.csdn.net/xgjians...
查看原文

赞 0 收藏 0 评论 0

soft_xiang 发布了文章 · 7月9日

ireport5.6.0+jasperreports 使用java对象做为数据源导出excel或者Pdf

ireport5.6.0安装不多说
安装完成后启动可能闪退,主要是ireport5.6.0需要jdk1.7才能运行,1.8就会闪退。

修改ireport jdk

修改 C:\Program Files (x86)\Jaspersoft\iReport-5.6.0\etc\ireport.conf (默认路径) 下

#jdkhome="/path/to/jdk"
jdkhome="C:\programs\Java\jdk1.7.0_71"

模版

image.png
image.png

① 对应代码中paramMap中的变量
② 对应代码中datas中的数据的名称
③ 计算数,需要注意计算类型
image.png
image.png

注意事项

  • 数据中有中文需要设置字体,否则可能打印不出来。

image.png

  • .jasper是.jrxml编译过后的文件

QQ截图20200709112535.png

  • 数据源设置

image.png
image.png

java代码

public static void main(String[] args) {
        String exportType = "xlsx";
        String defaultTemplatePath = "D:\\report1.jasper";
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("usid", "test@test.cn");
        paramMap.put("usna", "张三");
        paramMap.put("curDate", DateUtil.date2String(new Date()));
        List<Map<String, ?>> datas = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            Map<String, Object> temp = new HashMap<>();
            temp.put("key1", "key----" + i);
            temp.put("val1", "val====" + i);
            temp.put("cnt", 1);
            datas.add(temp);
        }
        JRDataSource dataSource = new JRMapCollectionDataSource(datas);
        try {
            JasperPrint jasperPrint = JasperFillManager.fillReport(defaultTemplatePath, paramMap, dataSource);
            String targetFileName = "D:\\test_" + DateUtil.date2String(new Date(), DateUtil.yyyyMMddHHmmss) + "." + exportType;
            if ("pdf".equalsIgnoreCase(exportType)) {
                JasperExportManager.exportReportToPdfFile(jasperPrint, targetFileName);
            } else if ("xlsx".equalsIgnoreCase(exportType)) {
                JRXlsxExporter exporter = new JRXlsxExporter();
                SimpleXlsxReportConfiguration configuration = new SimpleXlsxReportConfiguration();
                configuration.setWhitePageBackground(true);
                configuration.setRemoveEmptySpaceBetweenRows(true);// 空行
                configuration.setRemoveEmptySpaceBetweenColumns(true);// 空列
                exporter.setConfiguration(configuration);
                // 设置输入项
                ExporterInput exporterInput = new SimpleExporterInput(jasperPrint);
                exporter.setExporterInput(exporterInput);
                // 设置输出项
                OutputStreamExporterOutput exporterOutput = new SimpleOutputStreamExporterOutput(targetFileName);
                exporter.setExporterOutput(exporterOutput);
                exporter.exportReport();
            }
            System.out.println("导出成功:" + targetFileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

效果预览

image.png

查看原文

赞 0 收藏 0 评论 0

soft_xiang 发布了文章 · 6月3日

springboot项目将第三方jar、配置文件打包到jar包外部

springboot项目默认打成一个jar包,在多环境时不友好,需要将依赖的第三方jar及resources目录下的配置文件打包到与jar包同级目录下,方便环境变更,具体操作如下:

打包到外部目录

  1. pom.xml需修改

     <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <appendAssemblyId>false</appendAssemblyId>
                    <descriptors>
                        <descriptor>src/main/assembly/assembly.xml</descriptor>
                    </descriptors>
                    <outputDirectory>${project.build.directory}/gwall/</outputDirectory>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
    
            <!-- 打包成jar文件,并指定lib文件夹以及resources资源文件夹 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.xxl.job.admin.XxlJobAdminApplication</mainClass>
                            <!--依赖前缀 -->
                            <classpathPrefix>lib/</classpathPrefix>
                            <addClasspath>true</addClasspath>
                        </manifest>
                        <manifestEntries>
                            <Class-Path>resources/</Class-Path>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
  2. 添加配置文件
    image.png
    assembly.xml文件内容如下:

    <assembly
    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
    
    <id>distribution</id>
    
    <!--输出格式 zip 最终结果生成zip -->
    <formats>
        <format>tar.gz</format>
    </formats>
    
    <includeBaseDirectory>false</includeBaseDirectory>
    
    <!--设置需要输出文件 -->
    <fileSets>
        <fileSet>
            <directory>src/main/bin</directory>
            <outputDirectory>/</outputDirectory>
            <fileMode>0755</fileMode>
        </fileSet>
        <fileSet>
            <directory>src/main/resources/</directory>
            <outputDirectory>/resources</outputDirectory>
            <fileMode>0644</fileMode>
        </fileSet>
    </fileSets>
    
    <dependencySets>
        <dependencySet>
            <!--依赖包的输出目录 -->
            <outputDirectory>/lib</outputDirectory>
            <scope>runtime</scope>
            <excludes>
                <exclude>${project.groupId}:${project.artifactId}</exclude>
            </excludes>
        </dependencySet>
        <dependencySet>
            <!--jar包的输出目录 -->
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>${project.groupId}:${project.artifactId}</include>
            </includes>
        </dependencySet>
    </dependencySets></assembly>

    start.sh文件内容如下:

    #!/bin/bash
    curpath=`pwd`
    app=xxl-job-admin-2.1.0.jar
    echo 'curpath:$curpath    app:$app'
    ps -aux|grep $curpath/$app|grep -v grep|awk '{print $2}'|xargs -r kill -9
    nohup java  -jar $curpath/$app > $curpath/nohup.out 2>&1 &

    start.bat文件内容如下:

    @echo off & setlocal enabledelayedexpansion
    java -jar xxl-job-admin-2.1.0.jar
    pause

    最终结果如下:

    image.png
    image.png
    image.png

    注意问题

    logback不生效

    主要是使用logback-spring.xml
    另外需要在application.yml中配置

     logging:
       config: config/logback-spring.xml

    参见:
    https://my.oschina.net/u/2022...

查看原文

赞 0 收藏 0 评论 0

soft_xiang 发布了文章 · 5月26日

MyCat踩坑记录

mycat在使用过程中觉得非常好,很实用,但使用过程中也碰到了不少问题,踩了不少坑,现做一些记录,历史的一些坑已经忘记了,从现在开始吧

全局表

数据不同步

这个问题比较常见,而且比较初级。
现象为:连mycat的查询的时候多次执行SQL,返回的结果数量不一致或者数据不一致。
一般原因为:查询的表中有全局表,且在全局表中的数据不一致造成

Unknown command

重现现象为:项目中使用了mybatisplus(推荐,封装了mybatis的工具),在使用mybatisplus的saveOrUpdateBatch方法时,数据量超过一定的数据量时报 Unknown command,详细异常信息如下:

发生异常,
org.apache.ibatis.exceptions.PersistenceException: 
### Error flushing statements.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Unknown command
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Unknown command
    at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.flushStatements(DefaultSqlSession.java:254)
    at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.saveOrUpdateBatch(ServiceImpl.java:179)
    at com.baomidou.mybatisplus.extension.service.IService.saveOrUpdateBatch(IService.java:76)
    at com.gwall.core.service.impl.DstaskServiceImpl.saveOrUpdateCids(DstaskServiceImpl.java:148)
    at com.gwall.core.service.impl.DstaskServiceImpl$$FastClassBySpringCGLIB$$bf68f571.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:100)
    at com.gwall.core.common.aspects.GwallRequestIdAspect.requestIdHandle(GwallRequestIdAspect.java:46)
    at sun.reflect.GeneratedMethodAccessor83.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at com.gwall.core.service.impl.DstaskServiceImpl$$EnhancerBySpringCGLIB$$e5a8ece4.saveOrUpdateCids(<generated>)
    at com.gwall.core.service.impl.base.AbstractServiceImpl.batchSaveCids(AbstractServiceImpl.java:727)
    at com.gwall.core.service.impl.base.AbstractServiceImpl$$FastClassBySpringCGLIB$$3afa95e6.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:100)
    at com.gwall.core.common.aspects.GwallRequestIdAspect.requestIdHandle(GwallRequestIdAspect.java:46)
    at sun.reflect.GeneratedMethodAccessor83.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at com.gwall.base.service.impl.SuinServiceImpl$$EnhancerBySpringCGLIB$$946e8cf5.batchSaveCids(<generated>)
    at com.gwall.core.controller.AbstractController.batchSaveCids(AbstractController.java:500)
    at com.gwall.core.controller.AbstractController$$FastClassBySpringCGLIB$$9007052b.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:100)
    at com.gwall.core.common.aspects.GwallRequestIdAspect.requestIdHandle(GwallRequestIdAspect.java:46)
    at sun.reflect.GeneratedMethodAccessor83.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at com.gwall.base.controller.SuinController$$EnhancerBySpringCGLIB$$3fb28a8b.batchSaveCids(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at com.dianping.cat.servlet.CatFilter.logTransaction(CatFilter.java:255)
    at com.dianping.cat.servlet.CatFilter.doFilter(CatFilter.java:93)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:151)
    at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:85)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

将数据库连接改为mysql 3306端口时,则正常,定位为mycat问题,咨询大佬后给出的方案是将 数据库连接字符串?后的部分去掉。具体如
原数据库连接字符串:
jdbc:mysql://host:8066/db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&useAffectedRows=true&autoReconnect=true&failOverReadOnly=false
修改后:
jdbc:mysql://host:8066/db
问题修复,暂时只做问题记录,未研究具体原因

查看原文

赞 2 收藏 0 评论 0

soft_xiang 发布了文章 · 3月26日

springboot cache 自定义过期时间及自定义缓存key前缀

本篇文章主要是springboot2 中 redis cache中的一些内容,主要包含2个功能点:

  1. 自定义缓存过期时间(全局自定义,每个key不能单独指定)
  2. 自定义缓存key前缀

废话不多说,上代码

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
    private static final String SYSTEMCACHE_REDIS_KEY_PREFIX = "system:cache";
    private static final String SYSTEMCACHE_TTL_OFDAY = "system.cache.ttlOfDay";
    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    @Override
    public CacheManager cacheManager() {
        // 设置系统缓存过期时间为默认30天以及添加自定义前缀
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(
                        Duration.ofDays(30))
                .computePrefixWith(cacheKeyPrefix()); // 设置缓存有效期一小时
        return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
                .cacheDefaults(redisCacheConfiguration).build();
    }

    @Bean
    public CacheKeyPrefix cacheKeyPrefix() {
        return new CacheKeyPrefix() {
            @Override
            public String compute(String cacheName) {
                String cid = getCid();//此方法需要自己实现,获取租户编码
                StringBuilder sBuilder = new StringBuilder(100);
                sBuilder.append(SYSTEMCACHE_REDIS_KEY_PREFIX).append(":");
                if (StringUtil.isNotBlank(cid)) {
                    sBuilder.append(cid).append(":");
                }
                sBuilder.append(cacheName).append(":");
                return sBuilder.toString();
            }
        };
    }
}

用法:

@Cacheable(value = {"MenuTreeByRoles"})
    public List<Map<String, Object>> selectMenuTreeByRoles(String roleIds) {...}

则最终以生成system:cache:cid:MenuTreeByRoles为key的缓存;

查看原文

赞 1 收藏 0 评论 0

soft_xiang 发布了文章 · 1月8日

java poi sax方式处理大数据量excel文件

系统需要用到一个导入excel文件的功能,使用poi组件常规方式读取excel时,内存耗尽,OutOfMemoryError,或者读取非常慢
所以写了一个工具类,使用poi sax方式读取excel,速度快很多,内存消耗可以接受。

测试结果如下:
.xlsx文件,35M大小,总4个sheel,
只读取第一个,37434行,54列

总行数:37434
读取耗时:39秒
打印耗时:17秒

主要代码如下:
ExcelUtils.class 主入口

package com.xxx.bi.utils.excel;

import java.util.List;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;

import com.google.common.collect.Lists;

public class ExcelUtils {
    /** logger日志. */
    // public static final Logger LOGGER = Logger.getLogger(ExcelUtils.class);

    public ExcelUtils() {
    }

    /**
     * 获取excel的表头
     * 
     * @param filePath
     *            文件路径
     * @param headerNum
     *            表头所在行数
     * @return
     */
    public static List<String> getHeader(String filePath, int headerNum) {
        if (StringUtils.isBlank(filePath)) {
            throw new IllegalArgumentException("传入文件路径不能为空");
        }
        if (Objects.isNull(headerNum) || headerNum < 1) {
            headerNum = 1;
        }
        try {
            return LargeExcelFileReadUtil.getRowFromSheetOne(filePath, headerNum);
        } catch (Exception e) {
            // LOGGER.info("获取excel[" + filePath + "]表头失败,原因:", e);
            e.printStackTrace();
        }
        return Lists.newArrayList();
    }

    /**
     * 获取excel的所有数据<br/>
     * 所有数据类型都是String<br/>
     * 会以第一行数据的列数为总列数,所以第一行的数据必须都不为空,否则可能出java.lang.IndexOutOfBoundsException
     * 
     * @param filePath
     *            文件路径
     * @param headerNum
     *            表头所在行数
     * @return
     */
    public static List<List<String>> getAllData(String filePath) {
        if (StringUtils.isBlank(filePath)) {
            throw new IllegalArgumentException("传入文件路径不能为空");
        }
        try {
            return LargeExcelFileReadUtil.getRowsFromSheetOne(filePath);
        } catch (Exception e) {
            // LOGGER.info("获取excel[" + filePath + "]表头失败,原因:", e);
            e.printStackTrace();
        }
        return Lists.newArrayList();
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        String filepath = "C:/Users/Administrator/Desktop/05-作业调配表 -快递.xlsx";
        // List<String> result = ExcelUtils.getHeader(filepath, 1);
        // for (String col : result) {
        // System.out.println(col);
        // }

        List<List<String>> result = ExcelUtils.getAllData(filepath);
        long end = System.currentTimeMillis();
        for (List<String> list : result) {
            System.out.println(list.toString());
        }
        long end1 = System.currentTimeMillis();
        try {
            Thread.sleep(1000l);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.err.println("总行数:" + result.size());
        System.err.println(("读取耗时:" + (end - start) / 1000) + "秒");
        System.err.println(("打印耗时:" + (end1 - end) / 1000) + "秒");
    }
}

LargeExcelFileReadUtil.class 真正的工具类

package com.xxx.bi.utils.excel;

import java.io.InputStream;
import java.util.List;
import java.util.Objects;

import org.apache.log4j.Logger;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

public class LargeExcelFileReadUtil {
    /** logger日志. */
    public static final Logger LOGGER = Logger.getLogger(LargeExcelFileReadUtil.class);

    // 处理一个sheet
    public static List<String> getRowFromSheetOne(String filename, Integer rowNum) throws Exception {
        InputStream inputStream = null;
        OPCPackage pkg = null;
        SingleRowHandler singleRowHandler = null;
        try {
            pkg = OPCPackage.open(filename);
            XSSFReader r = new XSSFReader(pkg);
            SharedStringsTable sst = r.getSharedStringsTable();
            singleRowHandler = new SingleRowHandler(sst, rowNum);
            XMLReader parser = XMLReaderFactory.createXMLReader("com.sun.org.apache.xerces.internal.parsers.SAXParser");
            parser.setContentHandler(singleRowHandler);
            inputStream = r.getSheet("rId1");
            InputSource sheetSource = new InputSource(inputStream);
            parser.parse(sheetSource);
            return singleRowHandler.getRow();
        } catch (Exception e) {
            String message = e.getMessage();
            if (Objects.nonNull(rowNum) && Objects.nonNull(singleRowHandler)
                    && SingleRowHandler.FINISH_ROW_MESSAGE.equalsIgnoreCase(message)) {
                // 获取某一行数据完成 ,暂时不知道怎么能终止excel解析,直接抛出了异常,实际是成功的
                return singleRowHandler.getRow();
            }
            throw e;
        } finally {
            if (Objects.nonNull(pkg)) {
                pkg.close();
            }
            if (Objects.nonNull(inputStream)) {
                inputStream.close();
            }
        }
    }

    // 处理一个sheet
    public static List<List<String>> getRowsFromSheetOne(String filename) throws Exception {
        InputStream inputStream = null;
        OPCPackage pkg = null;
        MultiRowHandler multiRowHandler = null;
        try {
            pkg = OPCPackage.open(filename);
            XSSFReader r = new XSSFReader(pkg);
            SharedStringsTable sst = r.getSharedStringsTable();
            multiRowHandler = new MultiRowHandler(sst);
            XMLReader parser = XMLReaderFactory.createXMLReader("com.sun.org.apache.xerces.internal.parsers.SAXParser");
            parser.setContentHandler(multiRowHandler);
            inputStream = r.getSheet("rId1");
            InputSource sheetSource = new InputSource(inputStream);
            parser.parse(sheetSource);
            return multiRowHandler.getRows();
        } catch (Exception e) {
            throw e;
        } finally {
            if (Objects.nonNull(pkg)) {
                pkg.close();
            }
            if (Objects.nonNull(inputStream)) {
                inputStream.close();
            }
        }
    }

}

SingleRowHandler.class 当行处理类,可以只获取表头或表格中的某一行数据

package com.xxx.bi.utils.excel;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;

import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SingleRowHandler extends DefaultHandler {
    public final static String FINISH_ROW_MESSAGE = "row data process finish";

    private Integer rowNum = null;// rowNum不为空时则标示只需要获取这一行的数据
    private int curRowNum = 1;
    private String cellType = "";
    private SharedStringsTable sst;
    private String lastContents;
    private boolean nextIsString;
    private String cellPosition;
    private List<String> row = new ArrayList<>();

    public List<String> getRow() {
        return row;
    }

    public SingleRowHandler(SharedStringsTable sst, Integer rowNum) {
        this.sst = sst;
        this.rowNum = rowNum;
    }

    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
        if (name.equals("c")) {
            cellPosition = attributes.getValue("r");
            // 这是一个新行
            if (Pattern.compile("^A[0-9]+$").matcher(cellPosition).find()) {
                curRowNum = Integer.valueOf(cellPosition.substring(1));
            }
            cellType = "";
            cellType = attributes.getValue("t");
            if ("s".equals(cellType)) {
                nextIsString = true;
            } else {
                nextIsString = false;
            }
        }
        // 清楚缓存内容
        lastContents = "";
        if (Objects.nonNull(rowNum) && curRowNum > rowNum) {
            // 获取某一行数据完成 ,暂时不知道怎么能终止excel解析,直接抛出了异常,实际是成功的
            throw new SAXException(FINISH_ROW_MESSAGE);
        }
    }

    public void endElement(String uri, String localName, String name) throws SAXException {
        if (nextIsString) {
            int idx = Integer.parseInt(lastContents);
            lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
            nextIsString = false;
        }

        if (name.equals("v")) {
            if (Objects.isNull(rowNum) || rowNum == curRowNum) {
                row.add(lastContents);
            }
        }
    }

    public void characters(char[] ch, int start, int length) throws SAXException {
        lastContents += new String(ch, start, length);
    }
}

MultiRowHandler.class 获取excel所有行的数据

package com.xxx.bi.utils.excel;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * 获取完整excel数据的handler<br/>
 * 
 * @author Administrator
 *
 */
public class MultiRowHandler extends DefaultHandler {
    private int curRowNum = 0;// 行号,从1开始
    private int curColIndex = -1;// 列索引,从0开始
    private int colCnt = 0;// 列数,取第一行列数做为列总数
    private String cellType = "";
    private SharedStringsTable sst;
    private String lastContents;
    private boolean nextIsString;
    private String cellPosition;
    private List<String> head = null;
    private List<String> curRowData = null;
    private boolean curRowIsBlank = true;// 当前是个空行
    private List<List<String>> rows = new ArrayList<>();

    public List<List<String>> getRows() {
        return rows;
    }

    public MultiRowHandler(SharedStringsTable sst) {
        this.sst = sst;
    }

    @Override
    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
        if (name.equals("c")) {
            cellPosition = attributes.getValue("r");
            curColIndex = getColIndex(cellPosition);
            // 这是一个新行
            if (isNewRow(cellPosition)) {
                curRowNum = getRowNum(cellPosition);
                if (2 == curRowNum && Objects.nonNull(curRowData)) {
                    head = curRowData;
                    colCnt = head.size();
                }
                curRowData = getBlankRow(colCnt);
            }
            cellType = "";
            cellType = attributes.getValue("t");
            if ("s".equals(cellType)) {
                nextIsString = true;
            } else {
                nextIsString = false;
            }
        }
        // 清楚缓存内容
        lastContents = "";
    }

    private boolean isNewRow(String cellPosition) {
        // 坐标以A开头,后面跟数字 或者坐标行和当前行不一致的
        boolean newRow = Pattern.compile("^A[0-9]+$").matcher(cellPosition).find();
        if (!newRow) {
            int cellRowNum = getRowNum(cellPosition);
            newRow = (cellRowNum != curRowNum);
        }
        return newRow;
    }

    /**
     * 根据列坐标获取行号,从1开始,返回0时标示出错
     * 
     * @param cellPosition
     *            列坐标,为A1,B23等
     * @return 行号,从1开始,返回0是为失败
     */
    private static int getRowNum(String cellPosition) {
        String strVal = Pattern.compile("[^0-9]").matcher(cellPosition).replaceAll("").trim();// 获取坐标中的数字
        if (StringUtils.isNotBlank(strVal)) {
            return Integer.valueOf(strVal);
        }
        return 0;
    }

    /**
     * 根据列坐标返回当前列索引,从0开始,返回-1时标示出错<br/>
     * A1->0; B1->1...AA1->26
     * 
     * @param cellPosition
     *            列坐标,为A1,B23等
     * @return 列索引,从0开始,返回-1是为失败,A1->0; B1->1...AA1->26
     */
    private static int getColIndex(String cellPosition) {
        int index = -1;
        int num = 65;// A的Unicode码
        int length = cellPosition.length();
        for (int i = 0; i < length; i++) {
            char c = cellPosition.charAt(i);
            if (Character.isDigit(c)) {
                break;// 确定指定的char值是否为数字
            }
            index = (index + 1) * 26 + (int) c - num;
        }
        return index;
    }

    /**
     * 返回一个全部为空字符串的空行
     * 
     * @param cnt
     * @return
     */
    private List<String> getBlankRow(int cnt) {
        List<String> result = new ArrayList<>(cnt);
        for (int i = 0; i < cnt; i++) {
            result.add(i, "");
        }
        curRowIsBlank = true;
        return result;
    }

    @Override
    public void endElement(String uri, String localName, String name) throws SAXException {
        if (nextIsString) {
            int idx = Integer.parseInt(lastContents);
            lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
            nextIsString = false;
        }

        if (name.equals("v")) {
            // System.out.println(MessageFormat.format("当前列定位:{0},当前行:{1},当前列:{2},当前值:{3}",
            // cellPosition, curRowNum,
            // curColIndex, lastContents));
            if (Objects.isNull(head)) {
                curRowData.add(lastContents);
            } else {
                curRowData.set(curColIndex, lastContents);
            }
            curRowIsBlank = false;
            // 这是一个新行
            if (isNewRow(cellPosition)) {
                if (Objects.nonNull(curRowData)) {
                    if (curRowIsBlank) {
                        curRowData.clear();// 如果当前行是空行,则清空当前行数据
                    }
                    rows.add(curRowData);
                }
            }

        }
    }

    @Override
    public void endDocument() throws SAXException {
        if (Objects.nonNull(curRowData) && !curRowIsBlank) {
            rows.add(curRowData);// 最后一行在上面不好加入,最后一行全是空行的不加入
        }
        super.endDocument();
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        lastContents += new String(ch, start, length);
    }

    @Override
    public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
        lastContents += "";
    }

    public static void main(String[] args) {
        System.out.println(getColIndex("BC2"));
    }
}
查看原文

赞 0 收藏 0 评论 0

soft_xiang 发布了文章 · 2019-12-13

springboot2中的全局异常处理(包含Intercepter中的异常)

说明
之所以写这篇文章,是因为在项目中处理全局异常是发现自定义Intercepter中的异常没发通过 @ControllerAdvice 捕获。
项目中使用 @ControllerAdvice 处理了controller中的异常,但发现在自定义拦截器( extends HandlerInterceptorAdapter )中抛出的异常没有被拦截,跳转到了/error下,所以想要重写/error请求,过程比较曲折,现将测试通过的代码进行记录。
最终结果如下:
file

package com.xxx.core.controller;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeStacktrace;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import lombok.extern.slf4j.Slf4j;

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
@Slf4j
public class CustomerExceptionController extends AbstractErrorController {
    private final ErrorProperties errorProperties;

    @Autowired
    public CustomerExceptionController(ErrorAttributes errorAttributes, ServerProperties serverProperties) {
        super(errorAttributes);
        this.errorProperties = serverProperties.getError();
    }

    @Override
    public String getErrorPath() {
        return errorProperties.getPath();
    }

    @RequestMapping(produces = "text/html")
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        ModelAndView modelAndView = new ModelAndView("error");
        Map<String, Object> errorMap = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
        if (errorMap != null) {
            /* timestamp status error message path */
            modelAndView.addObject("msg", errorMap.get("error"));
            modelAndView.addObject("statusCode", errorMap.get("status"));
            logHandler(errorMap);
        }
        return modelAndView;
    }

    @RequestMapping
    @ResponseBody
    public ResponseEntity<JsonResult<Map<String, Object>>> error(HttpServletRequest request) {
        Map<String, Object> errorMap = getErrorAttributes(request,
                isIncludeStackTrace(request, MediaType.APPLICATION_JSON));
        logHandler(errorMap);
        Map<String, Object> data = new HashMap<>();
        data.putAll(errorMap);
        data.remove("trace");
        // HttpStatus status = getStatus(request);
        return new ResponseEntity<>(JsonResult.failure("", data), HttpStatus.OK);
    }

    private void logHandler(Map<String, Object> errorMap) {
        log.error("url:{},status{},time:{},errorMsg:{}", errorMap.get("path"), errorMap.get("status"),
                errorMap.get("timestamp"), errorMap.get("message"));
    }

    protected boolean isIncludeStackTrace(HttpServletRequest request, MediaType produces) {
        IncludeStacktrace include = getErrorProperties().getIncludeStacktrace();
        if (include == IncludeStacktrace.ALWAYS) {
            return true;
        }
        if (include == IncludeStacktrace.ON_TRACE_PARAM) {
            return getTraceParameter(request);
        }
        return false;
    }

    private ErrorProperties getErrorProperties() {
        return this.errorProperties;
    }
}

本来想直接继承 BasicErrorController,重写error方法 完事,结果发现继承后启动报错,提示没有ErrorProperties。
后来找到一篇文章,构造方法中注入的是ServerProperties serverProperties(和本例类似),通过serverProperties获取ErrorProperties,修改后提示没有无参的构造方法。
心好累,不想努力了,就直接继承了AbstractErrorController,抄了一些BasicErrorController的内容成了上面的代码。完美解决了纠结的问题。

注意事项
拦截器中要排除 /error路径

@Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authorizeIntercepter).addPathPatterns("/**").excludePathPatterns("/login", "/login/**",
                "/static/**", "/webjars/**", "/swagger-ui.html/**", "/swagger-resources/**","/v2/**","/error");
    }
查看原文

赞 0 收藏 0 评论 2

soft_xiang 发布了文章 · 2019-11-15

记一次Tomcat证书由jks更换为pfx的艰辛过程

背景介绍

https不了解,对https双向认证更是一脸懵

客户方要求系统提供https的服务,一年前申请某网站的免费证书,下载后包含了各种web容器的证书,应用程序的web容器为tomcat8,最后选用了tomcat下的证书,为jks格式。
image.png

一年后免费服务到期,需要更换证书,客户申请了阿里云的证书,下载下来的格式为pfx,客户说只有这种格式的。坑已挖好。

操作记录

百度搜索结果说可以将pfx转换成jks
命令如下:

keytool -importkeystore -srckeystore xxx.pfx -destkeystore xxx.jks -srcstoretype PKCS12 -deststoretype JKS -srcstorepass xxx -deststorepass xxx -srcalias alias -destalias destalias

因为原来tomcat中配置了jks相关的信息,想着直接将新的jks的文件名和密码保持一致,直接替换原文件就可以了。结果被坑。

按原来的文件名、密码生成新证书后,启动tomcat,事实证明想的还是太简单。
报错信息如下:

15-Nov-2019 12:20:20.221 SEVERE [main] org.apache.coyote.AbstractProtocol.init Failed to initialize end point associated with ProtocolHandler ["http-nio-443"]
 java.security.UnrecoverableKeyException: Cannot recover key
    at sun.security.provider.KeyProtector.recover(Unknown Source)
    at sun.security.provider.JavaKeyStore.engineGetKey(Unknown Source)
    at sun.security.provider.JavaKeyStore$JKS.engineGetKey(Unknown Source)
    at java.security.KeyStore.getKey(Unknown Source)
    at sun.security.ssl.SunX509KeyManagerImpl.<init>(Unknown Source)
    at sun.security.ssl.KeyManagerFactoryImpl$SunX509.engineInit(Unknown Source)
    at javax.net.ssl.KeyManagerFactory.init(Unknown Source)
    at org.apache.tomcat.util.net.jsse.JSSESocketFactory.getKeyManagers(JSSESocketFactory.java:617)
    at org.apache.tomcat.util.net.jsse.JSSESocketFactory.getKeyManagers(JSSESocketFactory.java:546)
    .
    .
    .
    Caused by: org.apache.catalina.LifecycleException: Protocol handler initialization failed
    at org.apache.catalina.connector.Connector.initInternal(Connector.java:962)
    at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
    ... 12 more
Caused by: java.security.UnrecoverableKeyException: Cannot recover key
    at sun.security.provider.KeyProtector.recover(Unknown Source)
    at sun.security.provider.JavaKeyStore.engineGetKey(Unknown Source)

处理办法:
将新的jks的密码和pfx的密码保持一致,修改tomcat配置文件中的密码。

其实tomcat可以直接配置pfx格式证书,需要指定 keystoreType="PKCS12"
keystoreFile="/证书路径/名称.pfx" keystoreType="PKCS12" keystorePass="证书密码"
但这次的客户有做https双向认证,之前的代码已经写死支持jks证书库,所以需要生成jks

遇到的异常说明

密码错误异常

15-Nov-2019 11:59:55.017 SEVERE [main] org.apache.coyote.AbstractProtocol.init Failed to initialize end point associated with ProtocolHandler ["http-nio-443"]
 java.io.IOException: Keystore was tampered with, or password was incorrect
    at sun.security.provider.JavaKeyStore.engineLoad(Unknown Source)
    at sun.security.provider.JavaKeyStore$JKS.engineLoad(Unknown Source)
    .
    .
    .
    Caused by: java.security.UnrecoverableKeyException: Password verification failed
    ... 25 more

pfx和jks密码不匹配

异常信息如下:

15-Nov-2019 12:20:20.221 SEVERE [main] org.apache.coyote.AbstractProtocol.init Failed to initialize end point associated with ProtocolHandler ["http-nio-443"]
 java.security.UnrecoverableKeyException: Cannot recover key

双向认证

示例代码


import javax.net.ssl.*;
import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.KeyStore;


/**
 * #2
 * HTTPS 双向认证 - use truststore
 * 原生方式
 *
 * @Author soft_xiang
 * @Date 7/11/2017
 */
public class HttpsTruststoreNativeDemo {
    // 客户端证书路径,用了本地绝对路径,需要修改 调用方证书
    private final static String CLIENT_CERT_FILE = "D:\\xxx\\https\\xxx-ip.p12";
    // 客户端证书密码
    private final static String CLIENT_PWD = "pwd";
    // 信任库路径 (被调用方证书合集)
    private final static String TRUST_STRORE_FILE = "D:\\xxx\\https\\xxx.jks";
    // 信任库密码
    private final static String TRUST_STORE_PWD = "xxx";


    private static String readResponseBody(InputStream inputStream) throws IOException {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            StringBuffer sb = new StringBuffer();
            String buff = null;
            while ((buff = br.readLine()) != null) {
                sb.append(buff + "\n");
            }
            return sb.toString();
        } finally {
            inputStream.close();
        }
    }

    public static void httpsCall() throws Exception {
        // 初始化密钥库
        KeyManagerFactory keyManagerFactory = KeyManagerFactory
                .getInstance("SunX509");
        KeyStore keyStore = getKeyStore(CLIENT_CERT_FILE, CLIENT_PWD, "PKCS12");
        keyManagerFactory.init(keyStore, CLIENT_PWD.toCharArray());

        // 初始化信任库
        TrustManagerFactory trustManagerFactory = TrustManagerFactory
                .getInstance("SunX509");
        KeyStore trustkeyStore = getKeyStore(TRUST_STRORE_FILE, TRUST_STORE_PWD, "JKS");
        trustManagerFactory.init(trustkeyStore);

        // 初始化SSL上下文
        SSLContext ctx = SSLContext.getInstance("SSL");
        ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory
                .getTrustManagers(), null);
        SSLSocketFactory sf = ctx.getSocketFactory();

        HttpsURLConnection.setDefaultSSLSocketFactory(sf);
        String url = "post url";
        URL urlObj = new URL(url);
        HttpsURLConnection con = (HttpsURLConnection) urlObj.openConnection();
        con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
        con.setRequestProperty("Accept-Language", "zh-CN;en-US,en;q=0.5");
        con.setRequestProperty("Content-Type", "text/xml");
        con.setRequestMethod("POST");
        con.setRequestProperty("Content-Length", "0");
        con.setDoInput(true);
        con.setDoOutput(true);
        DataOutputStream os = new DataOutputStream(con.getOutputStream());
        os.write("".getBytes("UTF-8"), 0, 0);
        os.flush();
        os.close();
        con.connect();
        InputStream is = con.getInputStream();
        Integer code = con.getResponseCode();
        final String contentType = con.getContentType();
        System.out.println(code + ":" + contentType);
        String response = readResponseBody(is);
        System.out.println(response);
    }

    /**
     * 获得KeyStore
     *
     * @param keyStorePath
     * @param password
     * @return
     * @throws Exception
     */
    private static KeyStore getKeyStore(String keyStorePath, String password, String type)
            throws Exception {
        FileInputStream is = new FileInputStream(keyStorePath);
        KeyStore ks = KeyStore.getInstance(type);
        ks.load(is, password.toCharArray());
        is.close();
        return ks;
    }


    public static void main(String[] args) throws Exception {
        httpsCall();
    }

}

双向认证示例中可能碰到的问题

image.png
在允许调用的服务器,直接浏览器打开需要访问的地址,调用出现401,sap问题,协调sap解决

image.png
证书库密码错误

image.png
证书错误,确认sap加入信任库的证书和代码中调用的证书库中的证书是同一个

常用命令

keytool -import -alias xxx -file "xxx.der" -keystore xxx.jks -storepass pass
将证书导入信任库

keytool -export -alias xxx -keystore abc.jks -storepass pass -file xxx.cer
将证书库abc.jks中别名为xxx的证书导出为xxx.cer,cer客户端证书

keytool -import -alias xxx -file xxx.cer -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -storepass changeit -trustcacerts
将客户端证书导入jdk的默认信任库(cacerts为jdk默认信任库,导入之前记得备份)

查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 13 次点赞
  • 获得 10 枚徽章 获得 1 枚金徽章, 获得 2 枚银徽章, 获得 7 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2018-03-16
个人主页被 656 人浏览