Java常用工具类

2022/7/15

# GeoJson-wkt

<!--geojson wkt格式转换依赖-->
<dependency>
    <groupId>org.wololo</groupId>
    <artifactId>jts2geojson</artifactId>
    <version>0.17.0</version>
</dependency>
import com.fasterxml.jackson.databind.ObjectMapper;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.io.WKTWriter;
import org.wololo.geojson.GeoJSON;
import org.wololo.jts2geojson.GeoJSONReader;
import org.wololo.jts2geojson.GeoJSONWriter;
import java.io.IOException;

/**
 * @author lichengcan
 * @date 2022/7/15 16:51
 * @description geojson和wkt格式转换工具类
 */
public class GeoJsonConvertWktUtil {
    /**
     * geojson 转 geometry
     *
     * @param geojson
     * @return
     * @throws Exception
     */
    public static Geometry geojson2Geometry(String geojson) throws Exception {
        GeoJSONReader reader = new GeoJSONReader();
        Geometry geometry = reader.read(geojson);
        return geometry;
    }


    /**
     * geometry 转 geojson
     *
     * @param geometry
     * @return
     * @throws Exception
     */
    public static String geometry2Geojson(Geometry geometry) throws Exception {
        GeoJSONWriter writer = new GeoJSONWriter();
        GeoJSON json = writer.write(geometry);
        return json.toString();
    }


    /**
     * wkt 转 geometry
     *
     * @param wkt
     * @return
     * @throws Exception
     */
    public static Geometry wkt2Geometry(String wkt) throws Exception {
        WKTReader reader = new WKTReader();
        return reader.read(wkt);
    }

    /**
     * geometry 转 wkt
     *
     * @param geometry
     * @return
     * @throws Exception
     */
    public static String geometry2Wkt(Geometry geometry) throws Exception {
        WKTWriter writer = new WKTWriter();
        return writer.write(geometry);
    }


    /**
     * geojson 转 wkt
     *
     * @param geojson
     * @return
     * @throws Exception
     */
    public static String geojson2Wkt(String geojson) throws Exception {
        Geometry geometry = geojson2Geometry(geojson);
        return geometry2Wkt(geometry);
    }

    /**
     * wkt 转 geojson
     *
     * @param wkt
     * @return
     * @throws Exception
     */
    public static String wkt2Geojson(String wkt) throws Exception {
        Geometry geometry = wkt2Geometry(wkt);
        return geometry2Geojson(geometry);
    }

    /**
     * obj 转 json
     *
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> String obj2StringPretty(T obj) {
        ObjectMapper mapper = new ObjectMapper();
        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * json 转 obj
     *
     * @param str
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T string2Obj(String str, Class<T> clazz) {
        ObjectMapper mapper = new ObjectMapper();
        if (isEmpty(str) || clazz == null) {
            return null;
        }
        try {
            return clazz.equals(String.class) ? (T) str : mapper.readValue(str, clazz);
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * 为空判断
     *
     * @param str
     * @return
     */
    private static boolean isEmpty(String str) {
        return str == null || str.length() == 0;
    }

}

# 示例

geojson--->wkt读取jeojson文件,并插入数据库

@RestController
@RequestMapping("/shimen")
public class ShimenDownController {

    @Autowired
    ShimenTownService shimenTownService;

    @RequestMapping("/insertShimenDown")
    public ResultMap insertShimenDown() throws Exception {
        //读取文件
        File file=new File("D:\\documents\\work\\shimen_town_R_84_R(1).geojson");
        //读取文件中的数据保存在String
        String GeoJsonData= null;
        try {
            GeoJsonData = FileUtils.readFileToString(file,"UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        //将所有对象都放到集合中,再一次性插入数据库
        List<ShimenTown> shimenTowns = new ArrayList<>();

        //将JeoJson格式转换枨 map
        Map map =  JSONObject.parseObject(GeoJsonData.trim());
        //获取key为 features的值
        List<Map> features = (List<Map>) map.get("features");
        //resultMapList 用来封装最终需要的数据
        List<Map> resultMapList = new ArrayList<>();
        //遍历features中的map
        for (Map feature :features){
            Map geometry = (Map) feature.get("geometry");
            String geometryStr = JsonUtils.toJson(geometry);
            String wkt = geojson2Wkt(geometryStr);
            Map properties = (Map) feature.get("properties");
            //封装最小化插入数据库的对象,这里的对象一定要放在循环里面,不然在循环过程中会替换上一次的值
            //ArrayList集合里存的是一个对象的引用。当我们改变obj时,之前添加的数据都会被改变
            ShimenTown shimenTown = new ShimenTown();
            //封装需要插入数据库的数据
            shimenTown.setBSM((String) properties.get("BSM"));
            shimenTown.setWkt(wkt);
            shimenTown.setXZQDM((String) properties.get("XZQDM"));
            shimenTown.setXZQMC((String) properties.get("XZQMC"));
            shimenTowns.add(shimenTown);
        }
        //一次性插入数据库
        return shimenTownService.insertShimenDown(shimenTowns);
    }

# Java-Excel

<!--excel操作包-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>
<!--xlsx(07)-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>
<!--时间格式化工具-->
<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.10.6</version>
</dependency>

# 示例

package com.dataojo.utils;

import com.dataojo.model.entity.CityLocation;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.joda.time.DateTime;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author lichengcan
 * @date 2022/7/12 16:01
 * @description excel操作工具类
 */
public class ReadExcelXssf {

    public static String PATH = "D:\\documents\\work\\";

    public static void main(String[] args) throws Exception {
        ReadExcelXssf readExcelXssf = new ReadExcelXssf();
       // readExcelXssf.readExcel();
    }

    /**
     * 将Excel数据读取出来,封装到对象中
     * @return
     * @throws IOException
     */
    public List<CityLocation> readExcel() throws IOException {
        List<CityLocation> resultList = new ArrayList<>();
        CityLocation cityLocation = new CityLocation();
        //获取文件流
        FileInputStream inputStream = new FileInputStream(PATH + "成都轨迹叠加.xlsx");

        //1.创建工作簿,使用excel能操作的这边都看看操作
        Workbook workbook = new XSSFWorkbook(inputStream);
        //2.得到表
        Sheet sheet = workbook.getSheetAt(0);
        //3.得到行
        int rowLength = sheet.getLastRowNum();
        int columnLength = sheet.getRow(0).getPhysicalNumberOfCells();
        for (int i = 0; i < rowLength; i++) {
            for (int j = 0; j < columnLength; j++) {

                Row row = sheet.getRow(i);
                Cell cell = row.getCell(j);
                if(j==0){
                    String value = getValue(cell);
                    cityLocation.setParentId(value);
                }
                if(j==1){
                    String value = getValue(cell);
                    cityLocation.setLongitude(value);
                }
                if(j==2){
                    String value = getValue(cell);
                    cityLocation.setLatitude(value);
                }
                if(j==3){
                    String value = getValue(cell);
                    cityLocation.setCreateTime(value);
                }
            }
            //System.out.println(cityLocation);
            resultList.add(cityLocation);
        }
        inputStream.close();
        return resultList;
    }

    public static String getValue(Cell cell) {
        String cellValue = "";
        //匹配类型数据
        if (cell != null) {
            CellType cellType = cell.getCellType();
            switch (cellType) {
                case STRING: //字符串
                    cellValue = cell.getStringCellValue();
                    break;
                case BOOLEAN: //布尔类型
                    cellValue = String.valueOf(cell.getBooleanCellValue());
                    break;
                case BLANK: //空
                    break;
                case NUMERIC: //数字(日期、普通数字)
                    if (HSSFDateUtil.isCellDateFormatted(cell)) { //日期
                        Date date = cell.getDateCellValue();
                        cellValue = new DateTime(date).toString("yyyy-MM-dd");
                    } else {
                        //不是日期格式,防止数字过长
                        cell.setCellType(CellType.STRING);
                        cellValue = cell.toString();
                    }
                    break;
                case ERROR:
                    break;
                //default:
            }
        }
        return cellValue;
    }

    /**
     * 将数据输出到Excel
     * @param cityLocations
     * @throws IOException
     */
    public void printExcel(List<CityLocation> cityLocations) throws IOException {
        String PATH = "D:\\documents\\work\\";

        //时间
        long begin = System.currentTimeMillis();

        //创建一个工作簿
        Workbook workbook = new XSSFWorkbook();
        //创建表
        Sheet sheet = workbook.createSheet();
        //写入数据
        for (int rowNumber = 0; rowNumber < cityLocations.size(); rowNumber++) {
            CityLocation cityLocation = cityLocations.get(rowNumber);
            Row row = sheet.createRow(rowNumber);
            for (int cellNumber = 0; cellNumber <= 3; cellNumber++) {
                Cell cell = row.createCell(cellNumber);
                if(cellNumber==0){
                    cell.setCellValue(cityLocation.getParentId());
                }
                if(cellNumber==1){
                    cell.setCellValue(cityLocation.getLongitude());
                }
                if(cellNumber==2){
                    cell.setCellValue(cityLocation.getLatitude());
                }
                if(cellNumber==3){
                    cell.setCellValue(cityLocation.getCreateTime());
                }
            }
        }
        System.out.println("over");

        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "123.xlsx");
        workbook.write(fileOutputStream);
        fileOutputStream.close();
        long end = System.currentTimeMillis();
        System.out.println((double) (end - begin) / 1000);

    }

}
excel表中数据:
parentId	longitude	latitude	createTime
1	104.137318	30.668151	2020/12/2 0:00
1	104.1379449	30.66865906	2020/12/2 0:00
1	104.139973	30.67057863	2020/12/2 0:01
1	104.1401576	30.67075134	2020/12/2 0:01
1	104.1402878	30.67085149	2020/12/2 0:02
1	104.1403679	30.67092157	2020/12/2 0:02

# Java-时间戳

我们可以使用 util 包的 Date 类来获取当前时间戳。要以 yyyy.MM.dd 格式格式化时间戳,我们可以使用 SimpleDateFormat 类。请参见下面的示例。

import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleTesting{
    public static void main(String[] args) {
        SimpleDateFormat date = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
        String timeStamp = date.format(new Date());
        System.out.println("Current Time Stamp: "+timeStamp);
    }
}

# IP地址来源

1.导入工具类
  <dependency>
        <groupId>org.lionsoul</groupId>
        <artifactId>ip2region</artifactId>
        <version>1.7</version>
    </dependency>
import org.apache.commons.io.FileUtils;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.reflect.Method;

/**
 * @author MrBird
 */
public class AddressUtil {

    private static Logger log = LoggerFactory.getLogger(AddressUtil.class);

    public static String getCityInfo(String ip){

        File file;
        try {
            //db
            String dbPath = AddressUtil.class.getResource("/ip2region/ip2region.db").getPath();
             file= new File(dbPath);
            if (file.exists() == false) {
                String tmpDir = System.getProperties().getProperty("java.io.tmpdir");
                dbPath = tmpDir + "ip.db";
                file = new File(dbPath);
                FileUtils.copyInputStreamToFile(AddressUtil.class.getClassLoader().getResourceAsStream("classpath:ip2region/ip2region.db"), file);
            }

            //查询算法
            int algorithm = DbSearcher.BTREE_ALGORITHM; //B-tree
            //DbSearcher.BINARY_ALGORITHM //Binary
            //DbSearcher.MEMORY_ALGORITYM //Memory
            try {
                DbConfig config = new DbConfig();
                DbSearcher searcher = new DbSearcher(config, dbPath);

                //define the method
                Method method = null;
                switch (algorithm) {
                    case DbSearcher.BTREE_ALGORITHM:
                        method = searcher.getClass().getMethod("btreeSearch", String.class);
                        break;
                    case DbSearcher.BINARY_ALGORITHM:
                        method = searcher.getClass().getMethod("binarySearch", String.class);
                        break;
                    case DbSearcher.MEMORY_ALGORITYM:
                        method = searcher.getClass().getMethod("memorySearch", String.class);
                        break;
                }

                DataBlock dataBlock = null;
                if (Util.isIpAddress(ip) == false) {
                    System.out.println("Error: Invalid ip address");
                }

                dataBlock = (DataBlock) method.invoke(searcher, ip);

                return dataBlock.getRegion();

            } catch (Exception e) {
               // e.printStackTrace();
            }
        }catch (Exception e) {
            //e.printStackTrace();
        }finally {

        }

        return null;
    }
    public static void main(String[] args)  throws Exception{
        System.err.println(getCityInfo("127.0.0.1"));
        System.err.println(getCityInfo("17.1.1.3"));
    }
}

# Java-Http请求

/**
 * HTTP 请求模板
 * @return
 */
@Bean("restTemplate")
public RestTemplate restTemplate() {
    SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();

    //单位为ms
    factory.setReadTimeout(60000);
    factory.setConnectTimeout(60000);
    return new RestTemplate(factory);
}
@RestController
@RequestMapping("/data")
public class DataHandleController {

	@Autowired
    RestTemplate restTemplate;

    @RequestMapping("/getData")
    public ResultMap getData() {
        String url = "https://ldjsc.data.suqian.gov.cn//internalProcess/analyse/queryList";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
//      设置请求参数
        HashMap<String, Object> map = new HashMap<>();
        map.put("authCode", "1");
        //用HttpEntity封装整个请求报文
        HttpEntity<HashMap<String, Object>> request = new HttpEntity<>(map, headers);

//        开始调用
//        参数1:目标请求地址
//        参数2:请求体
//        参数3:目标请求接口的返回值类型(execute接口的返回值类型)
        Map resultMap = restTemplate.postForObject(url, request, Map.class);
        List<Map> dataList = (List<Map>) resultMap.get("data");

        List<Map> mapResult = new ArrayList<>();

        for (Map parentMap : dataList) {
            List<Map> mapList = (List<Map>) parentMap.get("judgmentList");
            //获取parentMap名称
            String name = (String) parentMap.get("name");
            for (Map sonMap : mapList) {
                sonMap.put("name",name);
                mapResult.add(sonMap);
            }
        }
        List<Map> sellAmount = mapResult.stream().sorted(Comparator.comparing((Map x) -> (Integer) x.get("id")).reversed()).collect(Collectors.toList());
        return Result.success(sellAmount);
    }

# Java-GeoJson

Java读取geojson格式文件数据

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
 @RequestMapping("/getGeoJsonData")
    public ResultMap getGeoJsonData(){
        //读取文件
        File file=new File("D:\\documents\\work\\shimen.geojson");
        //读取文件中的数据保存在String
        String content= null;
        try {
            content = FileUtils.readFileToString(file,"UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        //将String 转成Map对象
            Map map =  JSONObject.parseObject(content.trim());
            //获取key为 features的值
            List<Map> features = (List<Map>) map.get("features");
            //resultMapList 用来封装最终需要的数据
            List<Map> resultMapList = new ArrayList<>();
            //遍历features中的map
            for (Map feature :features){
                Map geometry = (Map) feature.get("geometry");
                Map properties = (Map) feature.get("properties");
                geometry.put("XZQMC", properties.get("XZQMC"));
                resultMapList.add(geometry);
            }
        return Result.success(resultMapList);
    }

# JWT-工具类

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.2.0</version>
        </dependency>
/**
 * @Author lichengcan
 * @Date 2020/3/1 09:18
 * @Version 1.0
 **/
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.io.UnsupportedEncodingException;
import java.util.Date;
public class JWTUtils {
    /**
     * 过期时间6小时
     */
    private static final long EXPIRE_TIME = 6 * 60 * 60 * 1000;

    /**
     * 校验token是否正确
     *
     * @param token  密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String username, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("username", username)
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成签名,2min后过期
     *
     * @param username 用户名
     * @param secret   用户的密码
     * @return 加密的token
     */
    public static String sign(String username, String secret) {
        try {
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 附带username信息
            return JWT.create()
                    .withClaim("username", username)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    /**
     * 判断过期
     *
     * @param token
     * @return
     */
    public static boolean isExpire(String token) {
        DecodedJWT jwt = JWT.decode(token);
        return System.currentTimeMillis() > jwt.getExpiresAt().getTime();
    }
}

# 验证码-工具类

package com.coderman.api.common.utils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

/**
 * 随机字符验证码生成工具类
 * @author Exrickx
 */
/**
 * Created by lichengcan on 2019/12/18 15:38
 */
public class CreateVerifyCode {
        /**
         * 图片的宽度
         */
        private int width = 160;
        /**
         * 图片的高度
         */
        private int height = 40;
        /**
         * 验证码字符个数
         */
        private int codeCount = 4;
        /**
         * 验证码干扰线数
         */
        private int lineCount = 20;
        /**
         * 验证码
         */
        private String code = null;
        /**
         * 验证码图片Buffer
         */
        private BufferedImage buffImg = null;

        Random random = new Random();

        public CreateVerifyCode() {
            creatImage();
        }

        public CreateVerifyCode(int width, int height) {
            this.width = width;
            this.height = height;
            creatImage();
        }

        public CreateVerifyCode(int width, int height, int codeCount) {
            this.width = width;
            this.height = height;
            this.codeCount = codeCount;
            creatImage();
        }

        public CreateVerifyCode(int width, int height, int codeCount, int lineCount) {
            this.width = width;
            this.height = height;
            this.codeCount = codeCount;
            this.lineCount = lineCount;
            creatImage();
        }

        public CreateVerifyCode(int width, int height, int codeCount, int lineCount, String code) {
            this.width = width;
            this.height = height;
            this.codeCount = codeCount;
            this.lineCount = lineCount;
            creatImage(code);
        }

        /**
         * 生成图片
         */
        private void creatImage() {
            // 字体的宽度
            int fontWidth = width / codeCount;
            // 字体的高度
            int fontHeight = height - 5;
            int codeY = height - 8;

            // 图像buffer
            buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g = buffImg.getGraphics();
            //Graphics2D g = buffImg.createGraphics();
            // 设置背景色
            g.setColor(getRandColor(200, 250));
            g.fillRect(0, 0, width, height);

            // 设置字体
            //Font font1 = getFont(fontHeight);
            Font font = new Font("Fixedsys", Font.BOLD, fontHeight);
            g.setFont(font);

            // 设置干扰线
            for (int i = 0; i < lineCount; i++) {
                int xs = random.nextInt(width);
                int ys = random.nextInt(height);
                int xe = xs + random.nextInt(width);
                int ye = ys + random.nextInt(height);
                g.setColor(getRandColor(1, 255));
                g.drawLine(xs, ys, xe, ye);
            }

            // 添加噪点
            float yawpRate = 0.01f;// 噪声率
            int area = (int) (yawpRate * width * height);
            for (int i = 0; i < area; i++) {
                int x = random.nextInt(width);
                int y = random.nextInt(height);

                buffImg.setRGB(x, y, random.nextInt(255));
            }

            String str1 = randomStr(codeCount);// 得到随机字符
            this.code = str1;
            for (int i = 0; i < codeCount; i++) {
                String strRand = str1.substring(i, i + 1);
                g.setColor(getRandColor(1, 255));
                // g.drawString(a,x,y);
                // a为要画出来的东西,x和y表示要画的东西最左侧字符的基线位于此图形上下文坐标系的 (x, y) 位置处
                g.drawString(strRand, i*fontWidth+3, codeY);
            }

        }

        /**
         * 生成指定字符图片
         */
        private void creatImage(String code) {
            // 字体的宽度
            int fontWidth = width / codeCount;
            // 字体的高度
            int fontHeight = height - 5;
            int codeY = height - 8;

            // 图像buffer
            buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g = buffImg.getGraphics();
            //Graphics2D g = buffImg.createGraphics();
            // 设置背景色
            g.setColor(getRandColor(200, 250));
            g.fillRect(0, 0, width, height);

            // 设置字体
            //Font font1 = getFont(fontHeight);
            Font font = new Font("Fixedsys", Font.BOLD, fontHeight);
            g.setFont(font);

            // 设置干扰线
            for (int i = 0; i < lineCount; i++) {
                int xs = random.nextInt(width);
                int ys = random.nextInt(height);
                int xe = xs + random.nextInt(width);
                int ye = ys + random.nextInt(height);
                g.setColor(getRandColor(1, 255));
                g.drawLine(xs, ys, xe, ye);
            }

            // 添加噪点
            float yawpRate = 0.01f;// 噪声率
            int area = (int) (yawpRate * width * height);
            for (int i = 0; i < area; i++) {
                int x = random.nextInt(width);
                int y = random.nextInt(height);

                buffImg.setRGB(x, y, random.nextInt(255));
            }

            this.code = code;
            for (int i = 0; i < code.length(); i++) {
                String strRand = code.substring(i, i + 1);
                g.setColor(getRandColor(1, 255));
                // g.drawString(a,x,y);
                // a为要画出来的东西,x和y表示要画的东西最左侧字符的基线位于此图形上下文坐标系的 (x, y) 位置处
                g.drawString(strRand, i*fontWidth+3, codeY);
            }

        }

        /**
         * 得到随机字符
         * @param n
         * @return
         */
        public String randomStr(int n) {
            String str1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
            String str2 = "";
            int len = str1.length() - 1;
            double r;
            for (int i = 0; i < n; i++) {
                r = (Math.random()) * len;
                str2 = str2 + str1.charAt((int) r);
            }
            return str2;
        }

        /**
         * 得到随机颜色
         * @param fc
         * @param bc
         * @return
         */
        private Color getRandColor(int fc, int bc) {
            // 给定范围获得随机颜色
            if (fc > 255){
                fc = 255;
            }
            if (bc > 255){
                bc = 255;
            }
            int r = fc + random.nextInt(bc - fc);
            int g = fc + random.nextInt(bc - fc);
            int b = fc + random.nextInt(bc - fc);
            return new Color(r, g, b);
        }

        /**
         * 产生随机字体
         */
        private Font getFont(int size) {
            Random random = new Random();
            Font font[] = new Font[5];
            font[0] = new Font("Ravie", Font.PLAIN, size);
            font[1] = new Font("Antique Olive Compact", Font.PLAIN, size);
            font[2] = new Font("Fixedsys", Font.PLAIN, size);
            font[3] = new Font("Wide Latin", Font.PLAIN, size);
            font[4] = new Font("Gill Sans Ultra Bold", Font.PLAIN, size);
            return font[random.nextInt(5)];
        }

        // 扭曲方法
        private void shear(Graphics g, int w1, int h1, Color color) {
            shearX(g, w1, h1, color);
            shearY(g, w1, h1, color);
        }

        private void shearX(Graphics g, int w1, int h1, Color color) {

            int period = random.nextInt(2);

            boolean borderGap = true;
            int frames = 1;
            int phase = random.nextInt(2);

            for (int i = 0; i < h1; i++) {
                double d = (double) (period >> 1)
                        * Math.sin((double) i / (double) period
                        + (6.2831853071795862D * (double) phase)
                        / (double) frames);
                g.copyArea(0, i, w1, 1, (int) d, 0);
                if (borderGap) {
                    g.setColor(color);
                    g.drawLine((int) d, i, 0, i);
                    g.drawLine((int) d + w1, i, w1, i);
                }
            }

        }

        private void shearY(Graphics g, int w1, int h1, Color color) {

            int period = random.nextInt(40) + 10; // 50;

            boolean borderGap = true;
            int frames = 20;
            int phase = 7;
            for (int i = 0; i < w1; i++) {
                double d = (double) (period >> 1)
                        * Math.sin((double) i / (double) period
                        + (6.2831853071795862D * (double) phase)
                        / (double) frames);
                g.copyArea(i, 0, 1, h1, 0, (int) d);
                if (borderGap) {
                    g.setColor(color);
                    g.drawLine(i, (int) d, i, 0);
                    g.drawLine(i, (int) d + h1, i, h1);
                }

            }

        }

        public void write(OutputStream sos) throws IOException {
            ImageIO.write(buffImg, "png", sos);
            sos.close();
        }

        public BufferedImage getBuffImg() {
            return buffImg;
        }

        public String getCode() {
            return code.toLowerCase();
        }
}