csv文件上传中文编码乱码的解决方法

下面是上传文件的截图:

QQ截图20180814094435

1.文件是以GB2312作为编号,当上传至服务端后,编码依然是GB2312。所以一开始我尝试以GB2312编码进行转码,但是结果是失败的。

2.后来想到了写出文件的时候进行转码,成功把文件转成了UTF-8,但是会出现其他的bug,比如数字“1”会变成“1              ”。也就是多了很多空格,所以也失败了。

3.最后想到了,分割字符串,组装成对象那块,开始依然尝试使用GB2312、GBK、UTF-8依然失败,最后使用编码:ISO-8859-1 成功了。

下面是代码片段:

@Override
public Object readLineMap(String line) throws IllegalServiceException {
    if (line.contains(",")) {
        String xline = null;
        try {
            xline = new String(line.getBytes("ISO-8859-1"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        logger(xline);
        String[] strings = xline.split(",");


        ...........................

Linux系统可能需要这样子:

xline = new String(line.getBytes("ISO-8859-1"),"GB2312");

一款性能监控好工具 – NewRelic

在读《高性能MySql》一书中,认识了NewRelic,但是还未能及时用上,所以在网上找了一个帖子以记录。

NewRelic是一家提供Rails性能监测服务的网站, NewRelic提供了不同级别的监测功能,免费的是Lite版本,最高有Gold版本.

New Relic工具有两种运行模式:

(1)Production 模式:当您的工程以生产模式运行时,您可以在rpm.newrelic.com 网站上实时对它进行监督。

(2)Developer模式:当您的工程以开发模式运行时,您可以在本地localhost:3000/newrelic网页上查看到性能分析数据。

 

New Relic工具安装步骤(默认Rails 3版本):

  1. gem install newrelic_rpm
  2. 在Gemfile文件中,添加gem ‘newrelic_rpm’语句

3.在当前工程下,bundle update

  1. 在newrelic.com/get-RPM.html注册Lite版本的账号,然后将从此网站下载到的newrelic.yml文件,复制到当前工程的config文件夹中。
  2. 在development模式下启动工程,访问工程,然后在http://localhost:3000/newrelic页面您会看到对当前工程的性能分析数据。

6.若在production模式下启动工程,则您访问http://localhost:3000/newrelic链接会失效,这时您可以通过https://rpm.newrelic.com/login进行登录,在NewRelic的网站上查看关于工程的性能分析数据。

基于 Swagger 的前后端分离开发实践

前后端分离开发已经是很流行的一个开发模式。前端开发不需要部署后端语言的环境,后端开发也不需要前端写好的任何程序。后端只管暴露各种 API 接口供给前端进行数据的增、删、改、查,不负责生成 HTML 页面,这种方式能够减轻后端任务让后端开发更加专注。尤其是在微服务的开发框架下, 前后端分离开发的模式应用更加广泛。本篇亦是在微服务的开发框架下的实践总结。

在微服务开发框架下,前端通常被设计成一个独立的微服务。前后端仅仅通过接口来协作,前端服务最终生成一个独立的 Docker 镜像来部署。在产品的核心微服务定义完成后,我们希望前后端 Service 同时开始开发,所以这里我们利用 Swagger 创建了一个基于 Node.js 的 Mock Server 作为前后端分离开发的工具。在后端服务没有完全实现的情况下, 使用 Mock Server 作为前端开发的支持工具, 来实现前后端同时开发的目的。

Java源码ImageVerifyUtils验证码工具类

应用于验证码校验与生成,一个简单的验证码生成类。

功能结合了,生成验证码,及验证码校验,需要传入http session。

直接上源码:

package com.mymvc.system.utils;

import com.mymvc.system.exception.IllegalValidateException;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.logging.Logger;

/**
 * image verify class.
 * <p>
 * ImageVerifyUtils verify = new ImageVerifyUtils();
 * verify.make(response, request.getSession());
 * <p>
 * verify.check(request.getSession(),code); => true or throw new Exception.
 */
public class ImageVerifyUtils {

    private static final Logger log = Logger.getLogger(ImageVerifyUtils.class.getName());

    private String KEY_SESSION_VERIFY = "key_session_image_verify";
    private String KEY_SESSION_DATETIME = "key_session_time_verify";

    private Long expireIn = 300000L;
    private String hash = "hash";

    //    private String raw = "qwertyupkijhgfdsazxcvbnmABCDEFGHJKLMNPQRSTUVWXYZ1234567890";
    private String raw = "1234567890";

    public ImageVerifyUtils() {

    }

    public void make(HttpServletResponse response, HttpSession session) throws Exception {
        this.make(response, session, 120, 40);
    }

    public void make(HttpServletResponse response, HttpSession session, int width, int height) throws Exception {
        this.make(response, session, width, height, 4);
    }

    /**
     * make a image verify
     * @param response output to browser.
     * @param session http session,use it to save verify code.
     * @param width default is 120px
     * @param height default is 40px
     * @param num the verify code.
     * @throws Exception
     */
    public void make(HttpServletResponse response, HttpSession session, int width, int height, int num) throws Exception {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        int r = this.getRandom(200, 255);
        int g = this.getRandom(200, 255);
        int b = this.getRandom(200, 255);

        Graphics2D g2d = (Graphics2D) image.getGraphics();
        g2d.setColor(new Color(r, g, b));
        g2d.fillRect(0, 0, width, height);

        g2d.setStroke(new BasicStroke(1.5f));
        for (int i = 0; i < 5; i++) {
            r = this.getRandom(50, 200);
            g = this.getRandom(50, 200);
            b = this.getRandom(50, 200);
            g2d.setColor(new Color(r, g, b));

            g2d.drawLine(getRandom(0, width), getRandom(0, height), getRandom(0, width), getRandom(0, height));
        }

        int fontSize = (width - 26) / num;

        r = this.getRandom(0, 180);
        g = this.getRandom(0, 180);
        b = this.getRandom(0, 180);
        g2d.setColor(new Color(r, g, b));
        g2d.setFont(new Font(null, Font.PLAIN, fontSize));
        List<String> codes = this.getVerifyString(num);
        String code = "";

        int __x = (width - fontSize * num) / 2;
        for (int i = 0; i < codes.size(); i++) {
            code += codes.get(i);
            if (i == 0) {
                g2d.drawString(codes.get(i), __x, getRandom(20, height));
            } else {
                g2d.drawString(codes.get(i), fontSize * i + __x, getRandom(20, height));
            }
        }

        log.info(">>code:" + code);
        //绘制干扰点
        g2d.setStroke(new BasicStroke(2.6f));
        for (int i = 0; i < 10; i++) {
            r = this.getRandom(100, 255);
            g = this.getRandom(100, 255);
            b = this.getRandom(100, 255);
            g2d.setColor(new Color(r, g, b));

            int x = getRandom(0, width);
            int y = getRandom(0, height);
            g2d.drawLine(x, y, x + 2, y + 2);
        }

        session.setAttribute(KEY_SESSION_VERIFY, Md5Utils.md5(code.toLowerCase() + hash).toUpperCase());
        session.setAttribute(KEY_SESSION_DATETIME, System.currentTimeMillis() + expireIn);

        response.setContentType("image/jpeg");
        OutputStream ops = response.getOutputStream();
        ImageIO.write(image, "jpeg", ops);
        ops.close();
    }

    /**
     * check the code valid or invalid.
     * @param session Http session
     * @param verifyCode code string
     * @return true or throws.
     * @throws IllegalValidateException
     */
    public boolean check(HttpSession session, String verifyCode) throws IllegalValidateException {

        if (verifyCode == null) {
            throw new IllegalValidateException("请输入验证码");
        }

        Long makeTime = (Long) session.getAttribute(KEY_SESSION_DATETIME);
        if (makeTime == null) {
            throw new IllegalValidateException("验证码不存在");
        }

        if (makeTime.longValue() < System.currentTimeMillis()) {
            throw new IllegalValidateException("验证码已过期");
        }

        String source = (String) session.getAttribute(KEY_SESSION_VERIFY);
        if (source == null) {
            throw new IllegalValidateException("验证码不存在");
        }

        String now = Md5Utils.md5(verifyCode.toLowerCase() + hash).toUpperCase();
        if (now.equals(source)) {
            session.removeAttribute(KEY_SESSION_DATETIME);
            session.removeAttribute(KEY_SESSION_VERIFY);
            return true;
        }

        throw new IllegalValidateException("验证码错误");

    }

    /**
     * get verify code.
     * @param num the code length,default is 4.
     * @return
     */
    private List<String> getVerifyString(int num) {
        if (num <= 0) {
            num = 4;
        }
        List<String> res = new ArrayList<>();
        Random r = new Random();
        for (int i = 0; i < num; i++) {
            res.add(String.valueOf(raw.charAt(r.nextInt(raw.length()))));
        }
        return res;
    }

    /**
     * get number by random.
     * @param min min number
     * @param max max number
     * @return between min to max.
     */
    private int getRandom(int min, int max) {
        Random random = new Random();
        return random.nextInt(max) % (max - min + 1) + min;
    }

}

 

使用方法(生成):

ImageVerifyUtils verify = new ImageVerifyUtils();
try {
    verify.make(response, request.getSession());
} catch (Exception e) {
    e.printStackTrace();
}

校验:

ImageVerifyUtils verify = new ImageVerifyUtils();
try {

    String code = request.getParameter("code");
    verify.check(request.getSession(),code);
} catch (IllegalValidateException e) {
    e.printStackTrace();
}

 

 

开源的许可证GPL、LGPL、BSD、Apache 2.0的通俗解释

软件开发者要开源软件,不单单是开放源代码就可以了,选择一种许可证很重要,一个许可证之于软件就相当于价值观之于普通人,代表了这个软件的基本品性。一个错误的许可证选择可能会直接导致整个项目的失败。

各种开源的许可证主要的限制还是在redistribution(发布),所以个人/商业公司开发的软件包含了GPL的代码,只要你不发布,是可以任意使用的。

下面是几个开源许可证的区别:

GPL
GPL软件的使用者有权力得到软件的代码,只要使用了GPL,在发布(redistribution)时,整个项目也必须是GPL的,即主程序和静态链接的库(linux的.a和Windows的.lib)必须是GPL的,动态链接库(Linux的.so,Windows的.dll)必须是GPL兼容的。所谓GPL兼容,也就是GPL软件中可以使用的库,这些许可证必须比GPL弱(如LGPL,BSD),而不能是某个商业许可证。正因如此,GPL是带有很强的传染性,只要你的软件使用了GPL的代码,那么就请以GPL开放源代码吧,并且你的项目中也不能有任何和GPL不兼容的库。

LGPL
GPL 带有很强的传染性,那么如果一个库使用GPL发布,那么使用这个库的所有软件也必须使用GPL发布,这对不想开放源代码的商业软件来讲是致命的打击——你可以不使用其他的库,但最基本的libc是无论如何绕不开的,如果libc是以GPL发布,就相当于所有软件必须以GPL发布了。所以,LGPL(Lesser GPL)诞生了。

LGPL定义为,在以LGPL发布的库的基础上开发新的库的时候,新的库必须以LGPL发布,但是如果仅仅是动态链接,那么则不受任何限制。这样商业软件就可以随意的使用LGPL的库了。因此,LGPL也具有传染性,但限制在其基础上开发的库上,而并不限制使用它的程序本身——它的传染性远小于GPL。

BSD、Apache 2.0
相对GPL/LGPL的开放源代码,BSD,Apache 2.0就宽松许多——商业软件可以任意的使用BSD,Apache 2.0发布的软件代码,而不需要开放源代码,只需要提及代码的原出处就可以了。BSD和Apache 2.0提及的方式稍有不同,具体可以参考协议的详细内容。它们是GPL兼容的

 

看看下面选择开源许可证的案例:

andorid 使用宽松的Apache 2.0发布,因为Google作为一个商业公司,并不想失去商业软件的支持,它希望团结一切可以团结的力量加入的Android的开发中来,壮大自己的阵营,使用Apache 2.0就无可厚非了。而Google本身,并没有丧失对Android的控制权,不会担心另外一个公司拿走了Android的代码开发出一个闭源 Android的对手。因为,只要Android不断的出新版,社区不停的跟进,并且不停的修改API,其他基于Android开发的公司不得不把自己的Patch提回到主干上,否则,必然将耗费大量人力物力在维护自己的Patch上(钱这方面你斗得过Google?),得不偿失。而且,闭源之后,与整个社区为敌,作为一个定位软件平台的项目,会流失大量应用软件开发者,以小博大,任何一个商业公司都不会干这种胜算不高的蠢事。
再看以GPL发布的Linux为什么比以BSD发布的FreeBSD成功。其实正是因为GPL的传染性。当一个开发人员在Linux基础上开发一个新功能之后, 不得不以GPL开放源代码,贡献回Linux,这样Linux本身才能越来也越壮大而且留住了相当的开发人员,形成了一个 优秀软件->很多使用者和贡献者->贡献->更优秀的软件->更多的使用者和贡献者… 的良性循环。

 

1234510