杂七杂八~~

1.根据经纬度判断距离

    /**
     * 计算距离
     * @param lng 经度
     * @param lat 纬度
     * @return
     */
    private double meter(BigDecimal lng1, BigDecimal lat1, BigDecimal lng, BigDecimal lat){
        double radiansAX = Math.toRadians(lng.doubleValue()); // 数据库经弧度
        double radiansAY = Math.toRadians(lat.doubleValue()); // 数据库纬弧度
        double radiansBX = Math.toRadians(lng1.doubleValue()); // 传入经弧度
        double radiansBY = Math.toRadians(lat1.doubleValue()); // 传入纬弧度
        double cos = Math.cos(radiansAY) * Math.cos(radiansBY) * Math.cos(radiansAX - radiansBX)
                + Math.sin(radiansAY) * Math.sin(radiansBY);
        double acos = Math.acos(cos); // 反余弦值
        return (6371000 * acos);
    }

SQL函数
在这里插入图片描述

2.判断某一时间是否在一个时间区间内

 /**
     *
     * @param sourceTime
     *            时间区间,半闭合,如[10:00-20:00)
     * @param curTime
     *            需要判断的时间 如10:00
     * @return
     * @throws IllegalArgumentException
     */
    public static boolean isInTime(String sourceTime, String curTime) {
        if (sourceTime == null || !sourceTime.contains("-") || !sourceTime.contains(":")) {
            throw new IllegalArgumentException("Illegal Argument arg:" + sourceTime);
        }
        if (curTime == null || !curTime.contains(":")) {
            throw new IllegalArgumentException("Illegal Argument arg:" + curTime);
        }
        String[] args = sourceTime.split("-");
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        try {
            long now = sdf.parse(curTime).getTime();
            long start = sdf.parse(args[0]).getTime();
            long end = sdf.parse(args[1]).getTime();
            if (args[1].equals("00:00")) {
                args[1] = "24:00";
            }
            if (end < start) {
                if (now >= end && now < start) {
                    return false;
                } else {
                    return true;
                }
            }
            else {
                if (now >= start && now < end) {
                    return true;
                } else {
                    return false;
                }
            }
        } catch (ParseException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("Illegal Argument arg:" + sourceTime);
        }

    }

3.计算日期为星期几

    public static Integer getWeek(String date) {
        String[] split = date.split("-");
        int year = Integer.parseInt(split[0]);
        int month = Integer.parseInt(split[1]);
        int day = Integer.parseInt(split[2]);

        boolean leap=year%400==0||year%100!=0&&year%4==0; //判断当年是否为闰年
        int total=year-1980+(year-1980+3)/4;//前几年的天数累积量
        for(int i=month-1;i>0;i--){
            switch(i){
                case 1:case 3:case 5:case 7:case 8:case 10:total+=31;break;
                case 4:case 6:case 9:case 11:total+=30;break;
                case 2:total+=leap?29:28;
            }
        }
        total+=day;
        int week=1;
        week=(week+total)%7;
        return week;
    }

4.判断今天是否超过某个日期

    public static boolean afterDate(Date date){
        String format = cn.hutool.core.date.DateUtil.format(date, "yyyy-MM-dd");
        //把String转为LocalDate
        LocalDate localTime=LocalDate.parse(format,DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        //判断当前日期是否大于指定日期
        return LocalDate.now().isAfter(localTime);
    }

5.计算两个日期的天数间隔

    public static Long dayGap(Date start,Date end) throws ParseException {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        //Date start = df.parse(df.format(new Date()));
        Long startTime = start.getTime();
        Long endTime = end.getTime();
        Long num=endTime-startTime;
        // System.out.println("相差天数为:"+num/24/60/60/1000);
        return num/24/60/60/1000;
    }

6.日期格式的转换

//根据系统时间获取当前日期 date转string
 public static String getdate()throws Exception{
            Date now = new Date(); 
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//可以方便地修改日期格式
            String hehe = dateFormat.format( now ); 
            return hehe;
}


//string转date
 public static Date StringToDate(String str) throws Exception {
            SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd");
            Date date = sdf.parse(str);
            return date;
}

7.计算当前时间与某个时间点的距离

DateUtil.formatDateTime2((System.currentTimeMillis() - e.getCreatedAt().getTime())/1000)+"前"
 /**
     * Java将秒换算成 时、分、秒格式
     *
     * @param s 秒
     * @return
     */
    public static String formatDateTime2(long s) {
        long day = (s / (60 * 60 * 24));
        long hours = (s / (60 * 60));
        long minutes = (s % (60 * 60)) / 60;
        long seconds = s % 60;
        if (day > 0) {
            return day + "天";
        }
        if (hours > 0) {
            return hours + "小时";
        }
        if (minutes > 0) {
            return minutes + "分钟";
        }
        if (seconds > 0) {
            return  seconds + "秒";
        }
        return "";
    }

8.二维码生成

    @Override
    public Object generateCode(SmlLnvitationParam param) {
        try {
            //通过appId和秘钥获取token
            String accessToken = getAccessToken();
            String scene = "id=" + param.getId();
            //调用微信接口生成二维码
            URL url = new URL("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            // 提交模式
            httpURLConnection.setRequestMethod("POST");
            httpURLConnection.setDoOutput(true);
            httpURLConnection.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            PrintWriter printWriter = new PrintWriter(httpURLConnection.getOutputStream());
            // 发送请求参数
            JSONObject paramJson = new JSONObject();
            //这就是你二维码里携带的参数 String型  名称不可变
            paramJson.put("scene", scene);
            //注意该接口传入的是page而不是path  扫描之后跳转的路径
            paramJson.put("page", param.getPath());
            //这是设置扫描二维码的宽度,单位 px,最小 280px,最大 1280px
//            paramJson.put("width", 200);
            //是否需要透明底色,为 true 时,生成透明底色的小程序  默认false
//            paramJson.put("is_hyaline", true);
            //自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调,默认 false
//            paramJson.put("auto_color", true);
            //要打开的小程序版本 正式版为 release,体验版为 trial,开发版为 develop
            paramJson.put("env_version", versions);
            //检查 page 是否存在 默认为ture检查page  false不检查page
            paramJson.put("check_path", false);
            printWriter.write(paramJson.toString());
            // flush输出流的缓冲
            printWriter.flush();

            //开始获取数据
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            InputStream inputStream = httpURLConnection.getInputStream();
            byte[] buffer = new byte[1024];
            int num = inputStream.read(buffer);
            while (num != -1) {
                baos.write(buffer, 0, num);
                num = inputStream.read(buffer);
            }
            baos.flush();
            byte[] bytes = baos.toByteArray();
            String base64EndByte = Base64Util.encode(bytes);
            base64EndByte = "data:image/png;base64," + base64EndByte;
            //byte转multipartFile
//            MultipartFile multipartFile = fileToMultifile(bytes, "邀请码.png");
            //上传图片  获取url
//            Result<Map<String, String>> fileUploadResourceDTOResult = fileService.upload(multipartFile, 1, true, null,
//                    "11.png", ScidContext.getScid());
//            Map<String, String> data = fileUploadResourceDTOResult.getData();
//            checkUploadResult(data);
            printWriter.close();
            inputStream.close();
            baos.close();
            Map<String,String> map = new HashMap<>(2);
//            map.put("url",data.get("url"));
            map.put("date",base64EndByte);

            //将返回的二维码流数据上传到oss 生成图片链接
            String filename = UploadUtil.uploadOne(inputStream, "qrcode.jpeg", bucketName, firstKey);
            String  codeUrl = "https://" + bucketName + "." + UploadUtil.endpoint.substring(UploadUtil.endpoint.indexOf("://") + 3) + "/" + firstKey + filename;

            return codeurl;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ScException("二维码生成失败");
        }
    }

获取token

    private String getAccessToken() throws IOException {
        String requestUrl =
                "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret" +
                        "=" + appKey;
        URL url = new URL(requestUrl);
        // 打开和URL之间的连接
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        // 设置通用的请求属性
        connection.setRequestProperty("Content-Type", "application/json");
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setUseCaches(false);
        connection.setDoOutput(true);
        connection.setDoInput(true);
        // 得到请求的输出流对象
        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
        out.writeBytes("");
        out.flush();
        out.close();

        // 建立实际的连接
        connection.connect();
        // 定义 BufferedReader输入流来读取URL的响应
        BufferedReader in;
        if (requestUrl.contains("nlp")) {
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "GBK"));
        } else {
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
        }
        StringBuilder result = new StringBuilder();
        String getLine;
        while ((getLine = in.readLine()) != null) {
            result.append(getLine);
        }
        in.close();
        JSONObject jsonObject = JSONObject.parseObject(result.toString());
        String accessToken = jsonObject.getString("access_token");
        return accessToken;
    }

9.微信小程序消息推送

创建发送模板
在这里插入图片描述

/**
     * 微信小程序通知发送
     *
     * @param userId
     * @param time
     * @param address
     * @param typeName
     */
    private void WechatSend(String userId, String time, String address, String typeName, String recordId) {


//构建要发送的消息内容  一个TemplateField代表一个列
        List<TemplateField> list = new ArrayList<>();

        TemplateField templateField1 = new TemplateField();
        templateField1.setName("thing1");
        templateField1.setValue("xxxx");
        list.add(templateField1);


        TemplateField templateField2 = new TemplateField();
        templateField2.setName("character_string2");
        templateField2.setValue(time);
        list.add(templateField2);

        TemplateField templateField3 = new TemplateField();
        templateField3.setName("thing3");
        templateField3.setValue(address);
        list.add(templateField3);

        TemplateField templateField4 = new TemplateField();
        templateField4.setName("thing4");
        templateField4.setValue("请前往签到或取消");
        list.add(templateField4);

        TemplateField templateField5 = new TemplateField();
        templateField5.setName("thing5");
        templateField5.setValue(typeName);
        list.add(templateField5);

        WxMsgDTO wxMsgDTO = new WxMsgDTO();
        wxMsgDTO.setUserId(userId);
        wxMsgDTO.setTemplateId(sendTemplateId);
        wxMsgDTO.setLink(pages+recordId);
        wxMsgDTO.setFields(list);
        iWechatService.Send(wxMsgDTO);
    }

发送

@Override
    public Result Send(WxMsg bean) {
    //发送的执行器
        Messages messages = wechatAccountUtil.getWechat(bean.getTargetId()).msg();
//发送的用户
        WxUserinfo wxUserinfo = wxUserinfoRepository.findFirstByUidAndTypeAndDeletedAtIsNull(bean.getUserId(),2);
        Long messageLong = messages.subscribeSendTemplate(wxUserinfo.getOpenid(), bean.getTemplateId(), bean.getLink(), bean.getFields(), null);
        return success(messageLong);
    }

    public Long subscribeSendTemplate(String accessToken, String openId, String templateId, String link, List<TemplateField> fields, MiniProgram miniProgram, String requestUrl) {
        checkNotNullAndEmpty(accessToken, "accessToken");
        checkNotNullAndEmpty(openId, "openId");
        checkNotNullAndEmpty(templateId, "templateId");

        String url = requestUrl + accessToken;
        Map<String, Object> params = buildSubscribeParams(openId, templateId, link, fields, miniProgram);

        Map<String, Object> resp = doPost(url, params);
        Object msgId = resp.get("msgid");
        return msgId instanceof Long ? (Long) msgId : ((Integer) msgId).longValue();
    }

构建参数

private Map<String, Object> buildSubscribeParams(String openId, String templateId, String link, List<TemplateField> fields, MiniProgram miniProgram) {
        Map<String, Object> params = Maps.newHashMapWithExpectedSize(4);
        params.put("touser", openId);
        params.put("template_id", templateId);
        if (!Strings.isNullOrEmpty(link)) {
            params.put("page", link);
        }
        if (!ObjectUtils.isEmpty(miniProgram)) {
            params.put("miniprogram", miniProgram);
        }
        if (fields != null && !fields.isEmpty()) {
            Map<String, Map<String, String>> data = Maps.newHashMapWithExpectedSize(fields.size());
            Map<String, String> dataItem;
            for (TemplateField field : fields) {
                dataItem = Maps.newHashMapWithExpectedSize(2);
                dataItem.put("value", field.getValue());
                dataItem.put("color", field.getColor());
                data.put(field.getName(), dataItem);
            }
            params.put("data", data);
        }
        return params;
    }

10.AOP+注解实现日志入参出参打印

思路:
一个注解类, 一个切面类。使用环绕通知,将入参出参打印出来,可以根据实际情况,有些接口只需要打印即可,有些需要打印并保存到数据库。

注解类GmLog

/**
 * 自定义日志注解
 * 1.运行时 使用使用注解
 * 2.注解作用于方法上
 * 3.注解是否将包含在 JavaDoc 中
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD };)
@Documented
public @interface GmLog {

    // 打印日志描述信息
    String value() default "";
    // TODO 是否保存到数据库
    boolean isSave() default false;
};

切面类LogAspect

里面有两种方式,一个是拦截添加注解的方法(适合新建项目,写接口的时候加上注解),一个是指定的包名下面所有的接口(适合现有项目,不必要改变其余代码)

/**
 * 用于记录注解上接口的入参出参,统一规范。
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    /**
     * 方法一: 不需要自定义注解, 直接拦截所有controller的请求。全部打印
     * 定义切入点表达式
     * 第一个*号:表示返回类型, *号表示所有的类型。
     * 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包.
     * 第二个*号:表示类名,*号表示所有的类。
     * *(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数
     */
    @Pointcut("execution(public * top.gmaya.gmayaserviceadminimpl.system.controller..*.*(..))")
    public void privilege() {
    };

    /**
     * 方法二:拦截该注解标识的方法
     */
    @Pointcut("@annotation(top.gmaya.gmayaserviceadminimpl.system.annotation.GmLog)")
    public void logPointCut() {
    };

    /**
     * 环绕通知
     * @param pjd
     * @return
     * @throws Throwable
     */
    //    @Around("privilege()") // 第一种方式
    @Around("logPointCut()") // 第二种方式
    public Object arount(ProceedingJoinPoint pjd) throws Throwable {
        long startTime = System.currentTimeMillis();

        // 类名
        String className = pjd.getTarget().getClass().getName();
        // 获取执行的方法名称
        String methodName = pjd.getSignature().getName();

        // 1. 如果是使用的第二种方式,则判断该方法是否使用了改注解
        // 2. 如果是使用的第一种方式,直接注释即可。
        GmLog gmLog = this.getAnnotationLog(pjd);
        if (gmLog != null) {
            String value = gmLog.value();
            log.info("{};.{};()【{};】:===================", className, methodName, value);
        };

        Object[] args = pjd.getArgs();
        try {
            String params = JSON.toJSONString(args[0]);
            //打印请求参数参数
            log.info("{};.{};()【方法请求参数为】:{};", className, methodName, params);
        }; catch (Exception e) {
            log.info("{};.{};()【方法请求参数打印失败】:{};", className, methodName, e);
        };
        // 执行目标方法
        Object result = pjd.proceed();
        // 打印返回结果
        try {
            String s = JSON.toJSONString(result);
            log.info("{};.{};()【方法返回结果为】:{};", className, methodName, s);
        }; catch (Exception e) {
            log.info("{};.{};()【方法返回结果打印失败】:{};", className, methodName, e);
        };
        // 获取执行完的时间
        long time = System.currentTimeMillis() - startTime;
        log.info("{};.{};()【方法执行时长为】:{};{};", className, methodName, time, " ms");
        // 如果使用第一种方式,把这里注释掉
        // TODO 这里可以考虑新加一个异步方法,保存信息到数据库,入参,出参,请求人,请求时间,ip信息等,如果有异常,还有异常信息。
        if (gmLog != null) {
            boolean save = gmLog.isSave();
            if (save) {
                String val = gmLog.value();
                // 调用异步保存数据库方法
                int i = this.saveLog(pjd, time, val);
                if (i > 0) {
                    // 判断插入条数,大于0,保存成功。
                    log.info("{};.{};()【{};】:===================", className, methodName, "保存数据库成功!");
                };
            };
        };
        return result;
    };

    /**
     * 是否存在注解,如果存在就获取
     * @param joinPoint
     * @return
     */
    private GmLog getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(GmLog.class);
        };
        return null;
    };

    /**
     * 保存到数据库
     * @param joinPoint
     * @param time 方法执行时间 单位ms
     * @param val 方法请求描述
     * @return
     */
    private int saveLog(JoinPoint joinPoint, long time, String val) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
            .getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        JSONObject jsonObject = new JSONObject();
        // ip地址
        String hostAddress = "";
        try {
            hostAddress = InetAddress.getLocalHost().getHostAddress();
        }; catch (Exception e) {
            log.error("获取ip失败");
        };
        // redis.getUserId(); 结合实际情况 获取当前登录人信息
        // 类名
        String className = joinPoint.getTarget().getClass().getName();
        // 获取执行的方法名称
        String methodName = joinPoint.getSignature().getName();
        String url = request.getRequestURL().toString();
        String method = request.getMethod();
        jsonObject.put("ip", hostAddress);
        jsonObject.put("className", className);
        jsonObject.put("methodName", methodName);
        jsonObject.put("url", url);
        // 执行时间
        jsonObject.put("time", time);
        jsonObject.put("createTime", new Date());
        jsonObject.put("createUser", "GMaya");
        // 操作描述
        jsonObject.put("operation", val);
        jsonObject.put("method", method);
        String s = jsonObject.toJSONString();
        // 调用日志service的add方法即可!
        log.info(s);
        return 1;
    };

};

controller层接口展示:

//只需要添加注解即可,以及是否保存到数据库,默认不保存。
	@RequestMapping("add")
    @GmLog(value = "新增登录信息" , isSave = true)
    public R add(@RequestBody F<UserEntity> f) {
        // 登录用户信息
        UserEntity user = this.getUser(f.getToken());
        return R.data(userService.add(f,user));
    };

11.JSON格式的转换

@Data
public class Person implements Serializable {
private String name; // 姓名
private int salary; // 薪资
private int age; // 年龄
private String sex; //性别
private String area; // 地区

// 构造方法
// 省略了get和set,请自行添加

}

public class JsonTest {

    public static void main(String[] args) {

        Person person1 = new Person("张三",100,20,"男","广州");

        String personJson = JSONObject.toJSONString(person1);
        System.out.println("将实体类转为json字符串:"+personJson);

        JSONObject personJsonObject = (JSONObject) JSONObject.toJSON(person1);
        System.out.println("将实体类转为json对象:"+personJsonObject);


        Person person = JSONObject.parseObject(personJsonObject.toJSONString(), Person.class);
        System.out.println("json对象转某个对象:"+person.toString());

        System.out.println("上面方法会出现一个问题,某些值会丢失。替代方法,先转为Map,然后直接通过get取值");

        Map<String,Person> map = JSONObject.parseObject(personJsonObject.toJSONString(), Map.class);
        Set<String> strings=map.keySet();
        Iterator<String> iterator = strings.iterator();
        while (iterator.hasNext()){
            System.out.println(map.get(iterator.next()));
        }


        System.out.println("===================");
        String name = (String) personJsonObject.get("name");
        System.out.println("json对象的属性值:"+name);


        List<Person> personList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            Person p = new Person("张三",100,20+i,"男","广州");
            personList.add(p);
        }

        JSONArray personJsonArray = JSONObject.parseArray(JSONObject.toJSONString(personList));
        System.out.println("list转JSAONArray:"+personJsonArray);


        Map map1 = new HashMap();
        map1.put("one",person);
        map1.put("two",person1);
        JSONObject mapJsonObject = (JSONObject) JSONObject.toJSON(map1);
        System.out.println("map<string,object>转Json:"+mapJsonObject);


        String strJson = personJsonObject.toString();
        System.out.println("将JSONObject对象转为json字符串:"+strJson);
    }
}

在这里插入图片描述

12.通过地址获取经纬度(高德API)

/**
     * 根据地址信息获取经纬度,(高德api)
     */
    public static GisPoiDTO addressResolution (String address) {
        if (StringUtils.isBlank(address)) {
            throw new Exception("获取定位失败");
        }
        GisPoiDTO dto = new GisPoiDTO();
        String url = "https://restapi.amap.com/v3/geocode/geo";
        //构造接口需要的形参
        String param = "key=" + "4safgsfds333434ad34vf222s354l34l5md" +
                //活动id
                "&output=" + "JSON" +
                "&address=" + address;
        String result = HttpClientUtil.sendGet(url, param);
        JSONObject jsonObject = JSONObject.parseObject(result);
        if ("1".equals(jsonObject.get("status"))) {
            JSONArray jsonArray = jsonObject.getJSONArray("geocodes");
            if (!ObjectUtils.isEmpty(jsonArray)) {
                jsonObject = (JSONObject) jsonArray.get(0);
                String location = (String) jsonObject.get("location");
                String[] str = location.split(",");
                dto.setLng(str[0]);
                dto.setLat(str[1]);
            }
        } else {
            throw new ScException(RespCode.LOCATION_ERROR);
        }
        return dto;
    }
public class GisPoiDTO implements Serializable {
//===========================数据库字段================================
    /**
     * 区域块/线路
     */
    private String id;
    /**
     * 纬度
     */
    private String lat;
    /**
     * 经度
     */
    private String lng;
    /**
     * 地址
     */
    private String addr;
    /**
     * 备注
     */
    private String memo;
    /**
     * 创建时间
     */
    private Date createdAt;
    /**
     * 删除时间
     */
    private Date deletedAt;
    /**
     * 修改时间
     */
    private Date updatedAt;
    /**
     * 有效时间
     */
    private Date validTime;
    /**
     * 数据添加者
     */
    private String author;
//===========================表关联====================================


//===========================自定义字段================================
    /**
     * 地图类型:百度 google 84坐标
     */
    private String mapType;
    /**
     * 地区
     */
    private String district;

    public GisPoiDTO(String lat, String lng, String addr, String mapType) {
        this.lat = lat;
        this.lng = lng;
        this.addr = addr;
        this.mapType = mapType;
    }
}

13.通过ftl模板导出pdf

依赖

 <dependency>
			<groupId>org.freemarker</groupId>
			<artifactId>freemarker</artifactId>
			<version>2.3.28</version>
		</dependency>
 
 
		<dependency>
			<groupId>org.xhtmlrenderer</groupId>
			<artifactId>flying-saucer-pdf</artifactId>
			<version>9.0.8</version>
		</dependency>

项目中建立 template/font目录存放字体文件(arialuni.ttf、simsun.ttc)和图片(logo.png),模板文件
执法通知书.ftl 放在template目录下。
在这里插入图片描述

PDFUtil

@Slf4j
public class PDFUtil {
	private static Logger logger = LoggerFactory.getLogger(PDFUtil.class);

		public static ByteArrayOutputStream createPDF(Map<String,Object> data, String templateFileName) throws Exception {
		// 创建一个FreeMarker实例, 负责管理FreeMarker模板的Configuration实例
		Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
		// 指定FreeMarker模板文件的位置
		cfg.setClassForTemplateLoading(PDFUtil.class,"/template");
		ITextRenderer renderer = new ITextRenderer();
		try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
			// 设置 css中 的字体样式(暂时仅支持宋体和黑体) 必须,不然中文不显示
			renderer.getFontResolver().addFont("/template/fonts/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
			// 设置模板的编码格式
			cfg.setEncoding(Locale.CHINA, "UTF-8");
			// 获取模板文件
			Template template = cfg.getTemplate(templateFileName, "UTF-8");
			StringWriter writer = new StringWriter();

			// 将数据输出到html中
			template.process(data, writer);
			writer.flush();

			String html = writer.toString();
			// 把html代码传入渲染器中
			renderer.setDocumentFromString(html);
			renderer.layout();

			renderer.createPDF(out, false);
			renderer.finishPDF();
			out.flush();
			return out;
		}
	}

	public static void zip(ZipOutputStream zipStream, ByteArrayOutputStream fileStream, String filename) throws IOException {
		//放入代表
		zipStream.putNextEntry(new ZipEntry(filename));
		zipStream.write(fileStream.toByteArray());
		zipStream.closeEntry();
	}


 	/**
	 * pdf转图片二进制
	 * @param fileContent
	 * @return
	 * @throws IOException
	 */
	public static List<byte[]> pdfToImage(byte[] fileContent) throws IOException {
		List<byte[]> result = new ArrayList<>();
		try (PDDocument document = PDDocument.load(fileContent)) {
			PDFRenderer renderer = new PDFRenderer(document);
			for (int i = 0; i < document.getNumberOfPages(); ++i) {
				BufferedImage bufferedImage = renderer.renderImageWithDPI(i, 400);
				ByteArrayOutputStream out = new ByteArrayOutputStream();
				ImageIO.write(bufferedImage, "png", out);
				result.add(out.toByteArray());
			}
		}
		return result;
	}


}

模板文件protocolTemplate.ftl

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
        .law-notify {
            padding: 0 40px;
        }
        .title {
            text-align: center;
        }
        body{
            font-family: SimSun;
        }
        .place,
        .content-span {
            border-bottom: 1px solid #333;
            font-weight: bold;
        }
        .place {
            display: inline-block;
            padding: 20px 0 10px;
            margin-bottom: 30px;
        }
        .content {
            line-height: 36px;
            text-indent: 2em;
            text-align: justify;
        }
        .inscribe {
            margin: 36px 0;
            position: relative;
            height: 100px;
        }
        .inscribe-content {
            position: absolute;
            right: 0;
            text-align: right;
        }
        .cachet {
            position: absolute;
            top: 0;
            right: 0;
            opacity: 0.7;
        }
    </style>
</head>
<body>
<div class="law-notify">
    <h2 class="title">XXXXXXX</h2>
    <div class="place">${placeName}:</div>
    <div class="content">
        因你(单位)有
        <span class="content-span">${behavior}</span>
        违法行为, 经相关部门核查及警告,
        未做任何整改措施。
    </div>
    <div class="inscribe">
        <div class="inscribe-content">
            <p>XXXXX</p>
            <p>${date}</p>
            <img
                    src="data:image/png;base64,iVBORw0KGggAAAI8AAABkCAYAAAC/4GPSCC"
                    class="cachet"
            />
        </div>
    </div>
    <div class="contact">
        <p>联系电话:XXXX</p>
        <p>单位地址:XXXXXXXXXX</p>
    </div>
</div>
</body>
</html>
    public void exportPDF(SmlEnforcement bean) {
        List<RespDTO> content = query(bean).getContent();
        try {
            // 设置响应消息头,告诉浏览器当前响应是一个下载文件
            CommonUtil.getResponse().setContentType( "multipart/form-data");
            // 告诉浏览器,当前响应数据要求用户干预保存到文件中,以及文件名是什么 如果文件名有中文,必须URL编码
            String fileName = URLEncoder.encode("执法通知书.zip", "UTF-8");
            CommonUtil.getResponse().setHeader( "Content-Disposition", "attachment;filename=" + fileName);
            OutputStream out = CommonUtil.getResponse().getOutputStream();
            //将输出流转为压缩输出流
            ZipOutputStream zipStream = new ZipOutputStream(out);
            for (RespDTO dto : content) {
                Map<String,Object> data = new HashMap<>(3);
                String placeName = dto.getPlaceName();
                data.put("placeName",placeName);
                data.put("behavior",dto.getBehavior() == null ? null : dto.getBehavior());
                String format = DateUtil.format(dto.getIssueDate(), "yyyy年MM月dd日");
                data.put("date",format);
                //生成pdf获取输出流
                ByteArrayOutputStream pdf = PDFUtil.createPDF(data, "执法通知书.ftl");
                //pdf流放入压缩流
                PDFUtil.zip(zipStream,pdf,"执法通知书/"+format+"/"+placeName+".pdf");
                pdf.close();
            }
            zipStream.close();
            out.close();
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值