美文网首页
一些小问题解决

一些小问题解决

作者: YoRuo_ | 来源:发表于2017-06-12 16:51 被阅读1018次

    最近一段时间堕落了。 = =

    买了个PS4,天天晚上回家就玩游戏去了。 = =

    这篇以后用来记录一些小问题吧。


    MySQL 驱动版本不对 导致数据库bit类型字段异常

    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
        at com.mysql.cj.mysqla.MysqlaUtils.bitToLong(MysqlaUtils.java:68)
        at com.mysql.cj.core.io.MysqlTextValueDecoder.decodeBit(MysqlTextValueDecoder.java:231)
        at com.mysql.cj.jdbc.ResultSetRow.decodeAndCreateReturnValue(ResultSetRow.java:170)
        at com.mysql.cj.jdbc.ResultSetRow.getValueFromBytes(ResultSetRow.java:269)
        at com.mysql.cj.jdbc.BufferRow.getValue(BufferRow.java:349)
        at com.mysql.cj.jdbc.ResultSetImpl.getNonStringValueFromRow(ResultSetImpl.java:813)
        at com.mysql.cj.jdbc.ResultSetImpl.getBoolean(ResultSetImpl.java:904)
        at com.mysql.cj.jdbc.ResultSetImpl.getBoolean(ResultSetImpl.java:908)
    

    https://bugs.mysql.com/bug.php?id=81755


    MyBatis 查询返回插入后主键的值

    单个的insert语句 加个selectkey标签

        <insert id="insert" parameterType="mbxc.task.domain.TaskGroup">
            insert into task_group
            <trim prefix="(" suffix=")" suffixOverrides=",">
                `id`,
                `nick`,
                `type`,
                `field`,
            </trim>
            <trim prefix="values (" suffix=")" suffixOverrides=",">
                #{id,jdbcType=BIGINT},
                #{nick,jdbcType=VARCHAR},
                #{type,jdbcType=VARCHAR},
                #{field,jdbcType=CHAR},
            </trim>
            <selectKey resultType="java.lang.Long" keyProperty="id">
                SELECT @@IDENTITY AS id
            </selectKey>
        </insert>
    

    批量插入返回主键值 在 mybatis3.3.1 就已经支持了

    https://github.com/mybatis/mybatis-3/pull/547

        <insert id="insertBatch" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
            insert into task
            (
            `params`,
            `status`,
            `exit_code`,
            `group_id`,
            `message`,
            `date_created`,
            `last_updated`
            ) values
            <foreach collection="list" item="item" index="index" separator=" , ">
                (
                #{item.params,jdbcType=LONGVARCHAR},
                #{item.status,jdbcType=CHAR},
                #{item.exitCode,jdbcType=CHAR},
                #{item.groupId,jdbcType=BIGINT},
                #{item.message,jdbcType=LONGVARCHAR},
                #{item.dateCreated,jdbcType=TIMESTAMP},
                #{item.lastUpdated,jdbcType=TIMESTAMP})
            </foreach>
        </insert>
    

    服务报出Broken pipe 异常奔溃

    有天凌晨一个重要的服务突然宕机了。

    gray2log日志打印的是java-io-ioexception-broken-pipe

    org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe    
        at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:389)
        at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:426)
        at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:338)
        at org.apache.catalina.connector.OutputBuffer.close(OutputBuffer.java:291)
        at org.apache.catalina.connector.CoyoteOutputStream.close(CoyoteOutputStream.java:151)
        at org.apache.struts2.dispatcher.StreamResult.doExecute(StreamResult.java:305)
        at org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:186)
        at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:371)
        at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:275)
        at org.apache.struts2.interceptor.DeprecationInterceptor.intercept(DeprecationInterceptor.java:41)
        at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
        at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
        at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
        at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:167)
        at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
        at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
    

    测试的时候都很正常,最近的更新也确定不会引发这个问题。

    突然想起之前有一次部署的服务也出现过这个问题,原因是数据库地址是测试库的。

    最后发现是获取数据库链接时候获取不到造成的。询问服务商回答说最近机房网络环境不稳定线路在做整改。。。


    启动项目成功后又shutdown

    接手同事一个项目,要进行功能上的迭代

    2017-05-07 21:18:52.696  INFO 17475 --- [           main] mbxc.ShowcaseScheduleApplication         : Started ShowcaseScheduleApplication in 27.189 seconds (JVM running for 27.977)
    2017-05-07 21:18:52.697  INFO 17475 --- [       Thread-3] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@7dfd3c81: startup date [Sun May 07 21:18:46 CST 2017]; root of context hierarchy
    2017-05-07 21:18:52.700  INFO 17475 --- [       Thread-3] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 0
    2017-05-07 21:18:52.702  INFO 17475 --- [       Thread-3] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown
    2017-05-07 21:18:52.703  INFO 17475 --- [       Thread-3] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
    

    然后报了这个异常。。 查来查去没发现啥毛病。 Google也没有确切的答案。

    然后突然看到 配置类上面的注解 @Profile("product")

    知道了。。 我本地的application.properties 并没有指定 spring.profiles.active

    加载有 @Configuration 这个注解的类就相当于是空的。


    MySQL插入的数据量大小

    这两天在写一个迁移任务,600w条数据需要迁移。

    花了一天写完测试了两遍算是结束了。

    在读出数据解析处理后,插入的报了一个异常。这个异常之前也见过。

    Cause: com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large (8,425,663 > 4,194,304). You can change this value on the server by setting the 'max_allowed_packet' variable.
    ; SQL []; Packet for query is too large (8,425,663 > 4,194,304). You can change this value on the server by setting the 'max_allowed_packet' variable.; nested exception is com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large (8,425,663 > 4,194,304). You can change this value on the server by setting the 'max_allowed_packet' variable.
        at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:108)
        at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
        at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
        at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
        at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)
        at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
        at com.sun.proxy.$Proxy75.insert(Unknown Source)
        at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:278)
        at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:57)
        at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
        at com.sun.proxy.$Proxy91.insertBatchs(Unknown Source)
        at mbxc.mvc.service.SyncHistoryService.syncHandle(SyncHistoryService.java:67)
        at mbxc.mvc.service.SyncHistoryService$$FastClassBySpringCGLIB$$da69c9f7.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
        at mbxc.mvc.service.SyncHistoryService$$EnhancerBySpringCGLIB$$911bc562.syncHandle(<generated>)
        at java.util.ArrayList.forEach(ArrayList.java:1249)
        at mbxc.task.taskhandler.TaskExecutor.syncHistory(TaskExecutor.java:83)
    

    插入的数据大小太大了。

    1. 更改数据库max_allowed_packet的配置大小 https://dev.mysql.com/doc/refman/5.7/en/packet-too-large.html

      max_allowed_packet 默认为 16MB

    2. 对数据进行切分。


    对List<T>均匀拆分

    以前写过一个拆分List的Util。

         public static List<List<Long>> splitList(List<Long> list, int len) {
           if (list == null || list.size() == 0 || len < 1) {
             return null;
           }
    
           List<List<Long>> result = new ArrayList<>();
    
           int size = list.size();
           int count = (size + len - 1) / len;
           for (int i = 0; i < count; i++) {
             List<Long> subList = list.subList(i * len, ((i + 1) * len > size ? size : len * (i + 1)));
             result.add(subList);
           }
           return result;
         }
    

    并不是很好。

    在Guava中Lists有拆分的方法

    Lists.partition(list, size);

    附源码

         /**
          * Returns consecutive {@linkplain List#subList(int, int) sublists} of a list,
          * each of the same size (the final list may be smaller). For example,
          * partitioning a list containing {@code [a, b, c, d, e]} with a partition
          * size of 3 yields {@code [[a, b, c], [d, e]]} -- an outer list containing
          * two inner lists of three and two elements, all in the original order.
          *
          * <p>The outer list is unmodifiable, but reflects the latest state of the
          * source list. The inner lists are sublist views of the original list,
          * produced on demand using {@link List#subList(int, int)}, and are subject
          * to all the usual caveats about modification as explained in that API.
          *
          * @param list the list to return consecutive sublists of
          * @param size the desired size of each sublist (the last may be
          *     smaller)
          * @return a list of consecutive sublists
          * @throws IllegalArgumentException if {@code partitionSize} is nonpositive
          */
         public static <T> List<List<T>> partition(List<T> list, int size) {
           checkNotNull(list);
           checkArgument(size > 0);
           return (list instanceof RandomAccess)
               ? new RandomAccessPartition<>(list, size)
               : new Partition<>(list, size);
         }
    
         private static class Partition<T> extends AbstractList<List<T>> {
           final List<T> list;
           final int size;
    
           Partition(List<T> list, int size) {
             this.list = list;
             this.size = size;
           }
    
           @Override
           public List<T> get(int index) {
             checkElementIndex(index, size());
             int start = index * size;
             int end = Math.min(start + size, list.size());
             return list.subList(start, end);
           }
    
           @Override
           public int size() {
             return IntMath.divide(list.size(), size, RoundingMode.CEILING);
           }
    
           @Override
           public boolean isEmpty() {
             return list.isEmpty();
           }
         }
    
         private static class RandomAccessPartition<T> extends Partition<T> implements RandomAccess {
           RandomAccessPartition(List<T> list, int size) {
             super(list, size);
           }
         }
    

    对原有的list 根据下标进行拆分。最后返回的List中的 List中的 对象地址 还是 和传入的List相同。如果你对拆分前的List .clear()拆分拿到的List也会为空。


    查询order by 后返回的数据

    一开始很随意的用了这个语句 = = 还没有 使用 MAX()

    这样会返回 date_created 相同时 找到的第一条数据。

    select
    last_id
    from sync_info
    order by date_created desc limit 1
    

    然后我改成了 这个 当然也可以使用 MAX()

    select
    last_id
    from sync_info
    order by id desc limit 1
    

    对象转Map

    调用淘宝开发平台接口,有个接口请求参数很多很多,Content-Typeapplication/x-www-form-urlencoded

    一个一个的 @Field塞好蠢也好麻烦就用了@FieldMap,前端传过来的是一个json,那么@RequestBody转为对象后需要再转为Map就写了一个Util类。

    package mbxc.mvc.util;
    
    import com.google.common.base.CaseFormat;
    import com.google.common.base.Preconditions;
    import com.google.common.collect.Maps;
    
    import java.beans.BeanInfo;
    import java.beans.Introspector;
    import java.beans.PropertyDescriptor;
    import java.lang.reflect.Method;
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    import java.util.List;
    import java.util.Map;
    
    
    /**
     * Created by LXC on 2017/5/10.
     */
    public class MapUtils {
    
      private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
      public static Map<String, Object> objTransformMap(Object object, List<String> skipStrs) throws Exception {
        Preconditions.checkNotNull(object, "object must not be null !");
    
        Map<String, Object> map = Maps.newHashMap();
    
        BeanInfo info = Introspector.getBeanInfo(object.getClass());
        for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
          Method reader = pd.getReadMethod();
          if (reader != null
              && (skipStrs == null || !skipStrs.contains(pd.getName()))
              && !pd.getName().equals("class")) {
    
            Object value = reader.invoke(object);
            value = value instanceof LocalDateTime ? ((LocalDateTime) value).format(DATE_TIME_FORMATTER) : value;
            if (value != null) {
              map.put(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, pd.getName()), value);
            }
          }
        }
        return map;
      }
    }
    

    String 的 replace 和 replaceAll

    字符串替换的时候报错了一个错。

    java.util.regex.PatternSyntaxException: Unclosed character class near index 0
    [
    ^
        at java.util.regex.Pattern.error(Pattern.java:1955)
        at java.util.regex.Pattern.clazz(Pattern.java:2548)
        at java.util.regex.Pattern.sequence(Pattern.java:2063)
        at java.util.regex.Pattern.expr(Pattern.java:1996)
        at java.util.regex.Pattern.compile(Pattern.java:1696)
        at java.util.regex.Pattern.<init>(Pattern.java:1351)
        at java.util.regex.Pattern.compile(Pattern.java:1028)
        at java.lang.String.replaceAll(String.java:2223)
    

    很奇怪 = = 简单替换个字符串而已

    然后看了一下 replace 和 **replaceAll **的源码,

    如下。

        /**
         * Replaces each substring of this string that matches the given <a
         * href="../util/regex/Pattern.html#sum">regular expression</a> with the
         * given replacement.
         *
         * <p> An invocation of this method of the form
         * <i>str</i>{@code .replaceAll(}<i>regex</i>{@code ,} <i>repl</i>{@code )}
         * yields exactly the same result as the expression
         *
         * <blockquote>
         * <code>
         * {@link java.util.regex.Pattern}.{@link
         * java.util.regex.Pattern#compile compile}(<i>regex</i>).{@link
         * java.util.regex.Pattern#matcher(java.lang.CharSequence) matcher}(<i>str</i>).{@link
         * java.util.regex.Matcher#replaceAll replaceAll}(<i>repl</i>)
         * </code>
         * </blockquote>
         *
         *<p>
         * Note that backslashes ({@code \}) and dollar signs ({@code $}) in the
         * replacement string may cause the results to be different than if it were
         * being treated as a literal replacement string; see
         * {@link java.util.regex.Matcher#replaceAll Matcher.replaceAll}.
         * Use {@link java.util.regex.Matcher#quoteReplacement} to suppress the special
         * meaning of these characters, if desired.
         *
         * @param   regex
         *          the regular expression to which this string is to be matched
         * @param   replacement
         *          the string to be substituted for each match
         *
         * @return  The resulting {@code String}
         *
         * @throws  PatternSyntaxException
         *          if the regular expression's syntax is invalid
         *
         * @see java.util.regex.Pattern
         *
         * @since 1.4
         * @spec JSR-51
         */
        public String replaceAll(String regex, String replacement) {
            return Pattern.compile(regex).matcher(this).replaceAll(replacement);
        }
    
        /**
         * Replaces each substring of this string that matches the literal target
         * sequence with the specified literal replacement sequence. The
         * replacement proceeds from the beginning of the string to the end, for
         * example, replacing "aa" with "b" in the string "aaa" will result in
         * "ba" rather than "ab".
         *
         * @param  target The sequence of char values to be replaced
         * @param  replacement The replacement sequence of char values
         * @return  The resulting string
         * @since 1.5
         */
        public String replace(CharSequence target, CharSequence replacement) {
            return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
                    this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
        }
    

    replace : 是直接是纯字符替换。

    repalceAll : 是正则表达式替换,换进行转义。


    Excel解析工具类

    依赖jar

    compile group: 'org.apache.poi', name: 'poi-ooxml', version: '3.16'
    

    package mbxc.mvc.util;
    
    
    import com.google.common.collect.Lists;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.poi.hssf.usermodel.HSSFRow;
    import org.apache.poi.hssf.usermodel.HSSFSheet;
    import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    import org.apache.poi.ss.usermodel.Cell;
    import org.apache.poi.ss.usermodel.CellType;
    import org.apache.poi.xssf.usermodel.XSSFRow;
    import org.apache.poi.xssf.usermodel.XSSFSheet;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    
    import javax.servlet.http.HttpServletRequest;
    import java.io.IOException;
    import java.io.InputStream;
    import java.text.DecimalFormat;
    import java.util.List;
    
    /**
     * Created by LXC on 2017/5/10.
     */
    
    public class ExcelUtils {
    
      private static final String OFFICE_EXCEL_2003_POSTFIX = "xls";
    
      private static final String OFFICE_EXCEL_2010_POSTFIX = "xlsx";
    
      private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0");
    
      public static List<Long> readItemIdFromExcel(HttpServletRequest request) throws IOException {
        String typeNameFix = request.getHeader("X-File-Name");
        String type = MapUtils.getFileExt(typeNameFix);
    
        List<Long> list = null;
        if (OFFICE_EXCEL_2003_POSTFIX.equals(type.toLowerCase())) {
          list = readXls(request.getInputStream());
    
        } else if (OFFICE_EXCEL_2010_POSTFIX.equals(type.toLowerCase())) {
          list = readXlsx(request.getInputStream());
        }
        return list;
      }
    
      /**
       * .xls结尾的文件
       *
       * @param is 文件流
       * @return
       * @throws IOException
       */
      private static List<Long> readXlsx(InputStream is) throws IOException {
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook(is);
        List<Long> list = Lists.newArrayList();
    
        for (int numSheet = 0; numSheet < xssfWorkbook.getNumberOfSheets(); numSheet++) {
          XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(numSheet);
          if (xssfSheet == null) {
            continue;
          }
          for (int rowNum = 1; rowNum <= xssfSheet.getLastRowNum(); rowNum++) {
            XSSFRow xssfRow = xssfSheet.getRow(rowNum);
            if (xssfRow != null) {
              String result = getValue(xssfRow.getCell(0));
              if (StringUtils.isNotEmpty(result)) {
                list.add(Long.valueOf(result));
              }
            }
          }
        }
        return list;
      }
    
      /**
       * .xls结尾的文件
       *
       * @param is 文件流
       * @return
       * @throws IOException
       */
      private static List<Long> readXls(InputStream is) throws IOException {
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook(is);
        List<Long> list = Lists.newArrayList();
    
        for (int numSheet = 0; numSheet < hssfWorkbook.getNumberOfSheets(); numSheet++) {
          HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(numSheet);
          if (hssfSheet == null) {
            continue;
          }
          for (int rowNum = 1; rowNum <= hssfSheet.getLastRowNum(); rowNum++) {
            HSSFRow hssfRow = hssfSheet.getRow(rowNum);
            if (hssfRow != null) {
              String result = getValue(hssfRow.getCell(0));
              if (StringUtils.isEmpty(result)) {
                list.add(Long.valueOf(result));
              }
            }
          }
        }
        return list;
      }
    
      @SuppressWarnings("static-access")
      private static String getValue(Cell cell) {
        if (cell.getCellTypeEnum() == CellType.BOOLEAN) {
          return String.valueOf(cell.getBooleanCellValue());
        } else if (cell.getCellTypeEnum() == CellType.NUMERIC) {
          return String.valueOf(DECIMAL_FORMAT.format(cell.getNumericCellValue()));
        } else {
          return String.valueOf(cell.getStringCellValue());
        }
      }
    }
    

    求小于当前数字的斐波那契数列

      @Test
      public void fibonacci() {
        //1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368
        System.out.println("0 --- > " + fibonacciForLessThanNumber(0));
        System.out.println("1 --- > " + fibonacciForLessThanNumber(1));
        System.out.println("2 --- > " + fibonacciForLessThanNumber(2));
        System.out.println("3 --- > " + fibonacciForLessThanNumber(3));
        System.out.println("4 --- > " + fibonacciForLessThanNumber(4));
        System.out.println("5 --- > " + fibonacciForLessThanNumber(5));
        System.out.println("6 --- > " + fibonacciForLessThanNumber(6));
        System.out.println("7 --- > " + fibonacciForLessThanNumber(7));
        System.out.println("8 --- > " + fibonacciForLessThanNumber(8));
        System.out.println("9 --- > " + fibonacciForLessThanNumber(100));
    
        System.out.println("index 0  --- > " + fibonacciForIndex(0));
        System.out.println("index 1  --- > " + fibonacciForIndex(1));
        System.out.println("index 2  --- > " + fibonacciForIndex(2));
        System.out.println("index 3  --- > " + fibonacciForIndex(3));
        System.out.println("index 4  --- > " + fibonacciForIndex(4));
        System.out.println("index 5  --- > " + fibonacciForIndex(5));
        System.out.println("index 6  --- > " + fibonacciForIndex(6));
        System.out.println("index 7  --- > " + fibonacciForIndex(7));
        System.out.println("index 8  --- > " + fibonacciForIndex(8));
        System.out.println("index 9  --- > " + fibonacciForIndex(9));
        System.out.println("index 10  --- > " + fibonacciForIndex(10));
        System.out.println("index 11  --- > " + fibonacciForIndex(11));
      }
    
      private List<Long> fibonacciForLessThanNumber(long l) {
        List<Long> list = new ArrayList<>();
    
        if (l >= 0) {
          list.add(0L);
        }
    
        if (l >= 1) {
          LongStream.range(0, 2).forEach(i -> list.add(1L));
        }
    
        long current;
        long prePre = 1;
        long pre = 1;
    
        boolean flag = l > 1;
    
        while (flag) {
          if (l >= 2) {
            current = prePre + pre;
            prePre = pre;
            pre = current;
            if (current <= l) {
              list.add(current);
            } else {
              flag = false;
            }
          }
        }
        return list;
      }
    
      private long fibonacciForIndex(long n) {
        if (n <= 0) {
          return 0;
        }
    
        if (n <= 2) {
          return 1;
        }
    
        long pre = 1;
    
        long next = 1;
    
        long c = 2;
    
        for (int i = 3; i <= n; i++) {
          c = pre + next;
          pre = next;
          next = c;
        }
        return c;
      }
    

    Html代码转图片并裁剪

    突然遇到这个需求,找了很多jar都不尽如意。

    最后还是找到了一个,还走了一个不是坑的坑。 = =

    jar包:html2image

    错误的jar地址。http://mvnrepository.com/artifact/com.github.xuwei-k/html2image/0.1.0

    正确的jar地址。https://github.com/e-ucm/eadventure/tree/master/etc/repository/gui/ava/html2image

    方法调用:

      private static List<BufferedImage> resizeToHeight(BufferedImage image) {
        int width = image.getWidth();
        int height = image.getHeight() / 20;
    
        List<BufferedImage> images = Lists.newArrayList();
    
        IntStream.range(0, 20).forEach(i -> {
          BufferedImage ret = image.getSubimage(0, i * height, width, height);
          images.add(ret);
        });
        return images;
      }
    
      public static void main(String[] args) throws IOException {
        String htmlTxt = "<p style=\"text-align:center;\"><span style=\"font-size:15.0pt;\">0702-13</span></p>\n" +
            "\n" +
            "<p style=\"text-align:center;\"><span style=\"font-size:15.0pt;\">尺码:SML</span></p>\n" +
            "\n" +
            "<p style=\"text-align:center;\"><span style=\"font-family: lisu;\"><span style=\"color: rgb(69, 129, 142);\"><strong><span style=\"font-size: 24px;\">面料;衬衣弹力棉+黑色带弹力西装棉&nbsp;</span></strong></span></span><br />\n" +
            " <span style=\"font-size:15.0pt;\">尺码;SML</span><br />\n" +
            " <span style=\"font-size:15.0pt;\">小码;衬衣 胸围84 衣长59 肩34 袖56 半裙;裤腰66 臀围84 裙长50 马甲随衬衣尺寸</span><br />\n" +
            " <span style=\"font-size:15.0pt;\">中码;衬衣 胸围88 衣长60 肩35 袖57 半裙;裤腰70 臀围88 裙长51 马甲随衬衣尺寸</span><br />\n" +
            " <span style=\"font-size:15.0pt;\">大码;衬衣 胸围88 衣长60 肩36 袖58 半裙;裤腰74 臀围92 裙长52 马甲随衬衣尺寸</span></p>"+
            "<p><img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i1/93733667/TB2V0xIt9FjpuFjSspbXXXagVXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i4/93733667/TB2szRMt88kpuFjSspeXXc7IpXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i3/93733667/TB2tZOqt9FjpuFjSszhXXaBuVXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i3/93733667/TB2j4EvtMNlpuFjy0FfXXX3CpXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i4/93733667/TB2RAsStHtlpuFjSspfXXXLUpXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i4/93733667/TB2uYAZtR0kpuFjy1zdXXXuUVXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" height=\"384.8481308411215\" src=\"https://img.alicdn.com/imgextra/i3/93733667/TB2rPRMt88kpuFjSspeXXc7IpXa_!!93733667.jpg\" width=\"790\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i4/93733667/TB2iyITtHXlpuFjSszfXXcSGXXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i3/93733667/TB2KOITtHXlpuFjSszfXXcSGXXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i2/93733667/TB27wBetYJkpuFjy1zcXXa5FFXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i1/93733667/TB2dpJFt80kpuFjSsppXXcGTXXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i4/93733667/TB2qQ7FtNXlpuFjSsphXXbJOXXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i3/93733667/TB2m7wStHtlpuFjSspfXXXLUpXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i4/93733667/TB2.odstYXlpuFjy1zbXXb_qpXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i2/93733667/TB2fGcOtH0kpuFjy0FjXXcBbVXa_!!93733667.jpg\" /><br />\n" +
            " <img alt=\"undefined\" src=\"https://img.alicdn.com/imgextra/i4/93733667/TB2RyIltRNkpuFjy0FaXXbRCVXa_!!93733667.jpg\" /></p>";
        HtmlImageGenerator imageGenerator = new HtmlImageGenerator();
        imageGenerator.loadHtml(htmlTxt);
        BufferedImage imageNew = imageGenerator.getBufferedImage();
        
        List<BufferedImage> imageList = resizeToHeight(imageNew);
    
        for (int i = 0; i < imageList.size(); i++) {
          File outFile = new File("/Users/lxc/Desktop/temp/" + i + ".png");
          ImageIO.write(imageList.get(i), "png", outFile);
        }
      }
    

    第一个方法为裁剪图片,并未对原来的图片进行修改。而是重新创建了一个 BufferedImage 对象

        /**
         * Returns a subimage defined by a specified rectangular region.
         * The returned <code>BufferedImage</code> shares the same
         * data array as the original image.
         * @param x the X coordinate of the upper-left corner of the
         *          specified rectangular region
         * @param y the Y coordinate of the upper-left corner of the
         *          specified rectangular region
         * @param w the width of the specified rectangular region
         * @param h the height of the specified rectangular region
         * @return a <code>BufferedImage</code> that is the subimage of this
         *          <code>BufferedImage</code>.
         * @exception RasterFormatException if the specified
         * area is not contained within this <code>BufferedImage</code>.
         */
        public BufferedImage getSubimage (int x, int y, int w, int h) {
            return new BufferedImage (colorModel,
                                      raster.createWritableChild(x, y, w, h,
                                                                 0, 0, null),
                                      colorModel.isAlphaPremultiplied(),
                                      properties);
        }
    

    还有一个通过url拼接图片的方法:

      public static List<File> mergeAndCutPic(List<String> picList) {
        int length = picList.size();
        if (length < 1) {
          return null;
        }
        List<File> files = Lists.newArrayList();
        try {
          BufferedImage[] images = new BufferedImage[length];
          int[][] imageArr = new int[length][];
    
          for (int i = 0; i < length; i++) {
            images[i] = ImageIO.read(new URL(picList.get(i)).openStream());
            int width = images[i].getWidth();
            int height = images[i].getHeight();
            imageArr[i] = new int[width * height];
            imageArr[i] = images[i].getRGB(0, 0, width, height, imageArr[i], 0, width);
          }
    
          int tempHeight = 0;
          int tempWidth = images[0].getWidth();
    
          for (BufferedImage image : images) {
            tempWidth = tempWidth > image.getWidth() ? tempWidth : image.getWidth();
            tempHeight += image.getHeight();
          }
    
          if (tempHeight < 1) {
            return null;
          }
    
          BufferedImage imageNew = new BufferedImage(tempWidth, tempHeight,
              BufferedImage.TYPE_INT_RGB);
          int height = 0;
          for (int i = 0; i < images.length; i++) {
            imageNew.setRGB(0, height, tempWidth, images[i].getHeight(), imageArr[i], 0, tempWidth);
            height += images[i].getHeight();
          }
    
          List<BufferedImage> imageList = resizeToHeight(imageNew);
    
          for (BufferedImage image : imageList) {
            File outFile = new File("/Users/lxc/Desktop/temp/"
                + System.currentTimeMillis() + UUID.randomUUID() + ".png");
            ImageIO.write(image, "png", outFile);
            files.add(outFile);
          }
        } catch (Exception e) {
          return null;
        }
        return files;
      }
    

    相关文章

      网友评论

          本文标题:一些小问题解决

          本文链接:https://www.haomeiwen.com/subject/uaglqxtx.html