diff --git a/accompany-admin/accompany-admin-sdk/src/main/java/com/accompany/admin/dto/link/ShortLinkAdminDto.java b/accompany-admin/accompany-admin-sdk/src/main/java/com/accompany/admin/dto/link/ShortLinkAdminDto.java new file mode 100644 index 000000000..c7f6e7867 --- /dev/null +++ b/accompany-admin/accompany-admin-sdk/src/main/java/com/accompany/admin/dto/link/ShortLinkAdminDto.java @@ -0,0 +1,61 @@ +package com.accompany.admin.dto.link; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +/** + * @author: liaozetao + * @date: 2023/9/19 18:34 + * @description: + */ +@Data +public class ShortLinkAdminDto { + + /** + * 短链ID + */ + @ExcelProperty("短链ID") + private Long id; + + /** + * 短链名称 + */ + @ExcelProperty("短链名称") + private String name; + + /** + * 短链 + */ + @ExcelProperty("短链") + private String url; + + /** + * 二维码图片 + */ + @ExcelProperty("二维码图片") + private String qrcode; + + /** + * 定向跳转 + */ + @ExcelProperty("定向跳转") + private String typeName; + + /** + * 生成时间 + */ + @ExcelProperty("生成时间") + private String createTimeStr; + + /** + * 累计点击数 + */ + @ExcelProperty("累计点击数") + private Integer clickNum; + + /** + * 累计点击uv + */ + @ExcelProperty("累计点击uv") + private Integer uvNum; +} diff --git a/accompany-admin/accompany-admin-sdk/src/main/java/com/accompany/admin/vo/link/ShortLinkAdminVo.java b/accompany-admin/accompany-admin-sdk/src/main/java/com/accompany/admin/vo/link/ShortLinkAdminVo.java new file mode 100644 index 000000000..4b39ca5b3 --- /dev/null +++ b/accompany-admin/accompany-admin-sdk/src/main/java/com/accompany/admin/vo/link/ShortLinkAdminVo.java @@ -0,0 +1,28 @@ +package com.accompany.admin.vo.link; + +import com.accompany.business.model.link.ShortLink; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author: liaozetao + * @date: 2023/9/19 15:42 + * @description: + */ +@Data +@ApiModel +public class ShortLinkAdminVo extends ShortLink { + + /** + * 累计点击数 + */ + @ApiModelProperty("累计点击数") + private Integer clickNum = 0; + + /** + * 累计点击uv + */ + @ApiModelProperty("累计点击uv") + private Integer uvNum = 0; +} diff --git a/accompany-admin/accompany-admin-service/pom.xml b/accompany-admin/accompany-admin-service/pom.xml index 43646f936..03ae8d041 100644 --- a/accompany-admin/accompany-admin-service/pom.xml +++ b/accompany-admin/accompany-admin-service/pom.xml @@ -67,6 +67,11 @@ tomcat-embed-core compile + + com.google.zxing + javase + ${zxing.version} + \ No newline at end of file diff --git a/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/service/link/ShortLinkAdminService.java b/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/service/link/ShortLinkAdminService.java new file mode 100644 index 000000000..b39661882 --- /dev/null +++ b/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/service/link/ShortLinkAdminService.java @@ -0,0 +1,56 @@ +package com.accompany.admin.service.link; + +import com.accompany.admin.vo.link.ShortLinkAdminVo; +import com.accompany.business.model.link.ShortLink; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.springframework.web.context.request.ServletWebRequest; + +/** + * @author: liaozetao + * @date: 2023/9/19 15:35 + * @description: + */ +public interface ShortLinkAdminService { + + /** + * 分页 + * + * @param linkId + * @param linkName + * @param page + * @param pageSize + * @return + */ + Page page(Long linkId, String linkName, Integer page, Integer pageSize); + + /** + * 保存 + * + * @param param + */ + void save(ShortLink param); + + /** + * 失效 + * + * @param linkId + */ + void expire(Long linkId); + + /** + * 启用 + * + * @param linkId + */ + void enable(Long linkId); + + /** + * 导出 + * + * @param linkId + * @param linkName + * @param servletWebRequest + */ + void export(Long linkId, String linkName, ServletWebRequest servletWebRequest); + +} diff --git a/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/service/link/impl/ShortLinkAdminServiceImpl.java b/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/service/link/impl/ShortLinkAdminServiceImpl.java new file mode 100644 index 000000000..829a77aba --- /dev/null +++ b/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/service/link/impl/ShortLinkAdminServiceImpl.java @@ -0,0 +1,186 @@ +package com.accompany.admin.service.link.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.util.StrUtil; +import com.accompany.admin.dto.link.ShortLinkAdminDto; +import com.accompany.admin.service.link.ShortLinkAdminService; +import com.accompany.admin.util.QrCodeUtil; +import com.accompany.admin.vo.link.ShortLinkAdminVo; +import com.accompany.business.enums.link.ShortLinkTypeEnum; +import com.accompany.business.model.link.ShortLink; +import com.accompany.business.model.link.ShortLinkRecord; +import com.accompany.business.mybatismapper.link.ShortLinkMapper; +import com.accompany.business.mybatismapper.link.ShortLinkRecordMapper; +import com.accompany.business.service.api.QinniuService; +import com.accompany.common.constant.Constant; +import com.accompany.common.model.PageReq; +import com.accompany.core.service.SysConfService; +import com.alibaba.excel.EasyExcel; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.context.request.ServletWebRequest; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Random; + +/** + * @author: liaozetao + * @date: 2023/9/19 15:35 + * @description: + */ +@Slf4j +@Service +public class ShortLinkAdminServiceImpl implements ShortLinkAdminService { + + @Autowired + private ShortLinkMapper shortLinkMapper; + + @Autowired + private ShortLinkRecordMapper shortLinkRecordMapper; + + @Autowired + private QinniuService qinniuService; + + @Autowired + private SysConfService sysConfService; + + @Override + public Page page(Long linkId, String linkName, Integer currentPage, Integer pageSize) { + IPage page = shortLinkMapper.selectPage(new Page<>(currentPage, pageSize), Wrappers.lambdaQuery() + .eq(linkId != null, ShortLink::getId, linkId) + .like(StrUtil.isNotEmpty(linkName), ShortLink::getName, linkName) + .orderByDesc(ShortLink::getCreateTime)); + Page iPage = new Page<>(currentPage, pageSize); + List admins = new ArrayList<>(); + List records = page.getRecords(); + if (CollectionUtil.isNotEmpty(records)) { + for (ShortLink record : records) { + ShortLinkAdminVo admin = new ShortLinkAdminVo(); + BeanUtils.copyProperties(record, admin); + admin.setClickNum(shortLinkRecordMapper.selectCount(Wrappers.lambdaQuery() + .eq(ShortLinkRecord::getLinkId, record.getId()))); + //UV + admin.setUvNum(shortLinkRecordMapper.getUvCount(record.getId())); + admins.add(admin); + } + } + iPage.setTotal(page.getTotal()); + iPage.setRecords(admins); + return iPage; + } + + @Override + public void save(ShortLink param) { + String linkUrl = sysConfService.getSysConfValueById(Constant.SysConfId.SHORT_LINK_URL); + Long id = param.getId(); + Date now = new Date(); + param.setUpdateTime(now); + if (id == null) { + Random random = new Random(); + String code; + String qrcode = StrUtil.EMPTY; + for (code = Integer.toHexString(random.nextInt(900001) + 100000); + shortLinkMapper.selectCount(Wrappers.lambdaQuery() + .eq(ShortLink::getCode, code)) > 0; code = Integer.toHexString(random.nextInt(900001) + 100000)) + ; + code = code.toLowerCase(); + String url = linkUrl + code; + InputStream inputStream = null; + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + QrCodeUtil.encode(url, 200, 200, outputStream); + inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + qrcode = qinniuService.uploadByStream(inputStream); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + IOUtils.closeQuietly(inputStream); + } + param.setUrl(url); + param.setCode(code); + param.setQrcode(qrcode); + param.setCreateTime(now); + shortLinkMapper.insert(param); + } else { + shortLinkMapper.updateById(param); + } + } + + @Override + public void expire(Long linkId) { + ShortLink shortLink = shortLinkMapper.selectById(linkId); + if (shortLink == null) { + return; + } + shortLink.setIsEnabled(Constant.Yes1No0.NO); + shortLink.setExpireTime(new Date()); + shortLinkMapper.updateById(shortLink); + } + + @Override + public void enable(Long linkId) { + ShortLink shortLink = shortLinkMapper.selectById(linkId); + if (shortLink == null) { + return; + } + shortLink.setIsEnabled(Constant.Yes1No0.YES); + shortLink.setExpireTime(null); + shortLinkMapper.updateById(shortLink); + } + + @Override + public void export(Long linkId, String linkName, ServletWebRequest servletWebRequest) { + PageReq req = new PageReq(); + req.setPage(1); + req.setPageSize(1000000); + List datas = new ArrayList<>(); + Page page = page(linkId, linkName, 1, 100000); + List records = page.getRecords(); + if (CollectionUtil.isNotEmpty(records)) { + for (ShortLinkAdminVo record : records) { + Integer type = record.getType(); + Date createTime = record.getCreateTime(); + ShortLinkAdminDto admin = new ShortLinkAdminDto(); + BeanUtils.copyProperties(record, admin); + String typeName = "应用商店"; + if (type != null) { + if (type == ShortLinkTypeEnum.CUSTOM.ordinal()) { + typeName = "自定义URL:" + record.getCustomValue(); + } + } + admin.setTypeName(typeName); + if (createTime != null) { + admin.setCreateTimeStr(DateFormatUtils.format(createTime, DatePattern.NORM_DATETIME_PATTERN)); + } + datas.add(admin); + } + } + if (servletWebRequest.getResponse() != null) { + try { + //这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman + servletWebRequest.getResponse().setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + servletWebRequest.getResponse().setCharacterEncoding("utf-8"); + //这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 + String fileName = URLEncoder.encode("短链记录", "UTF-8").replaceAll("\\+", "%20"); + servletWebRequest.getResponse().setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); + EasyExcel.write(servletWebRequest.getResponse().getOutputStream(), ShortLinkAdminDto.class).sheet("短链记录").doWrite(datas); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + } + +} diff --git a/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/util/QrCodeUtil.java b/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/util/QrCodeUtil.java new file mode 100644 index 000000000..0e29a33de --- /dev/null +++ b/accompany-admin/accompany-admin-service/src/main/java/com/accompany/admin/util/QrCodeUtil.java @@ -0,0 +1,42 @@ +package com.accompany.admin.util; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Hashtable; +import java.util.Map; + +/** + * 二维码生成工具类 + */ +public class QrCodeUtil { + + /** + * 生成二维码 + * David + * + * @param url url 网址 + * @param width 二维码宽度 + * @param height 二维码高度 + */ + public static void encode(String url, int width, int height, OutputStream outputStream) { + Map hints = new Hashtable<>(); + // 指定纠错等级 + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); + // 指定编码格式 + hints.put(EncodeHintType.CHARACTER_SET, "UTF8"); + try { + BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, width, height, hints); + MatrixToImageWriter.writeToStream(bitMatrix, "png", outputStream); + } catch (Exception ignored) { + } + } + +} diff --git a/accompany-admin/accompany-admin-web/src/main/java/com/accompany/admin/controller/link/ShortLinkAdminController.java b/accompany-admin/accompany-admin-web/src/main/java/com/accompany/admin/controller/link/ShortLinkAdminController.java new file mode 100644 index 000000000..98b7f0c3a --- /dev/null +++ b/accompany-admin/accompany-admin-web/src/main/java/com/accompany/admin/controller/link/ShortLinkAdminController.java @@ -0,0 +1,101 @@ +package com.accompany.admin.controller.link; + +import com.accompany.admin.service.link.ShortLinkAdminService; +import com.accompany.admin.vo.link.ShortLinkAdminVo; +import com.accompany.business.model.link.ShortLink; +import com.accompany.common.model.PageReq; +import com.accompany.common.result.BusiResult; +import com.accompany.common.result.PageResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.ServletWebRequest; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @author: liaozetao + * @date: 2023/9/19 15:41 + * @description: + */ +@Api(tags = "短链管理") +@RestController +@RequestMapping("/admin/short/link") +public class ShortLinkAdminController { + + @Autowired + private ShortLinkAdminService shortLinkAdminService; + + /** + * 分页 + * + * @param linkId + * @param linkName + * @param req + * @return + */ + @ApiOperation("分页") + @GetMapping("page") + public PageResult page(Long linkId, String linkName, PageReq req) { + return new PageResult<>(shortLinkAdminService.page(linkId, linkName, req.getPage(), req.getPageSize())); + } + + /** + * 保存 + * + * @param param + * @return + */ + @ApiOperation("保存") + @PostMapping("save") + public BusiResult save(ShortLink param) { + shortLinkAdminService.save(param); + return BusiResult.success(); + } + + /** + * 失效 + * + * @param linkId + * @return + */ + @ApiOperation("失效") + @GetMapping("expire") + public BusiResult expire(Long linkId) { + shortLinkAdminService.expire(linkId); + return BusiResult.success(); + } + + /** + * 启用 + * + * @param linkId + * @return + */ + @ApiOperation("启用") + @GetMapping("enable") + public BusiResult enable(Long linkId) { + shortLinkAdminService.enable(linkId); + return BusiResult.success(); + } + + /** + * 导出 + * + * @param linkId + * @param linkName + * @param request + * @param response + */ + @ApiOperation("导出") + @PostMapping("export") + public void export(Long linkId, String linkName, HttpServletRequest request, HttpServletResponse response) { + shortLinkAdminService.export(linkId, linkName, new ServletWebRequest(request, response)); + } + +} diff --git a/accompany-admin/accompany-admin-web/src/main/resources/static/html/link/short_link.html b/accompany-admin/accompany-admin-web/src/main/resources/static/html/link/short_link.html new file mode 100644 index 000000000..357e6c8cf --- /dev/null +++ b/accompany-admin/accompany-admin-web/src/main/resources/static/html/link/short_link.html @@ -0,0 +1,282 @@ +
+
+
+ +
+

+
+ +
+
+
+
+ +
+ +
+ +
+ +
+
+
+ + + +
+
+
+
+ + + + + \ No newline at end of file diff --git a/accompany-admin/accompany-admin-web/src/main/resources/static/plugins/bootstrap-datetimepicker/js/locales/bootstrap-datetimepicker.zh-CN.js b/accompany-admin/accompany-admin-web/src/main/resources/static/plugins/bootstrap-datetimepicker/js/locales/bootstrap-datetimepicker.zh-CN.js deleted file mode 100644 index 418fb3071..000000000 --- a/accompany-admin/accompany-admin-web/src/main/resources/static/plugins/bootstrap-datetimepicker/js/locales/bootstrap-datetimepicker.zh-CN.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Simplified Chinese translation for bootstrap-datetimepicker - * Yuan Cheung - */ -;(function($){ - $.fn.datetimepicker.dates['zh-CN'] = { - days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], - daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"], - daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], - months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], - monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], - today: "今天", - suffix: [], - meridiem: ["上午", "下午"] - }; -}(jQuery)); diff --git a/accompany-base/accompany-core/src/main/java/com/accompany/common/constant/Constant.java b/accompany-base/accompany-core/src/main/java/com/accompany/common/constant/Constant.java index 74924394f..c939f0176 100644 --- a/accompany-base/accompany-core/src/main/java/com/accompany/common/constant/Constant.java +++ b/accompany-base/accompany-core/src/main/java/com/accompany/common/constant/Constant.java @@ -1824,6 +1824,10 @@ public class Constant { */ public static final String SMS_SDK_TYPE = "sms_sdk_type"; + /** + * 短链 + */ + public static final String SHORT_LINK_URL = "short_link_url"; } public static class ActiveMq { diff --git a/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/enums/link/ShortLinkTypeEnum.java b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/enums/link/ShortLinkTypeEnum.java new file mode 100644 index 000000000..4c92a527c --- /dev/null +++ b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/enums/link/ShortLinkTypeEnum.java @@ -0,0 +1,19 @@ +package com.accompany.business.enums.link; + +/** + * @author: liaozetao + * @date: 2023/9/19 17:03 + * @description: + */ +public enum ShortLinkTypeEnum { + + /** + * 应用商店 + */ + STORE, + + /** + * 自定义链接 + */ + CUSTOM; +} diff --git a/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/model/link/ShortLink.java b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/model/link/ShortLink.java new file mode 100644 index 000000000..b4ab894d2 --- /dev/null +++ b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/model/link/ShortLink.java @@ -0,0 +1,91 @@ +package com.accompany.business.model.link; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author: liaozetao + * @date: 2023/9/19 15:15 + * @description: + */ +@Data +@TableName("short_link") +public class ShortLink { + + + /** + * 主键 + */ + @ApiModelProperty("主键") + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 编码 + */ + @ApiModelProperty("编码") + private String code; + + /** + * 名称 + */ + @ApiModelProperty("名称") + private String name; + + /** + * 短链 + */ + @ApiModelProperty("短链") + private String url; + + /** + * 二维码 + */ + @ApiModelProperty("二维码") + private String qrcode; + + /** + * 类型 + */ + @ApiModelProperty("类型") + private Integer type; + + /** + * 自定义URL + */ + @ApiModelProperty("自定义URL") + private String customValue; + + /** + * 是否启用 0 失效 1 启用 + */ + @ApiModelProperty("是否启用 0 失效 1 启用") + private Integer isEnabled; + + /** + * 失效时间 + */ + @ApiModelProperty("失效时间") + private Date expireTime; + + /** + * 创建时间 + */ + @ApiModelProperty("创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + /** + * 更新时间 + */ + @ApiModelProperty("更新时间") + private Date updateTime; + +} diff --git a/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/model/link/ShortLinkRecord.java b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/model/link/ShortLinkRecord.java new file mode 100644 index 000000000..487fd6ef2 --- /dev/null +++ b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/model/link/ShortLinkRecord.java @@ -0,0 +1,77 @@ +package com.accompany.business.model.link; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author: liaozetao + * @date: 2023/9/19 15:15 + * @description: + */ +@Data +@TableName("short_link_record") +public class ShortLinkRecord { + + + /** + * 主键 + */ + @ApiModelProperty("主键") + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 短链ID + */ + @ApiModelProperty("短链ID") + private Long linkId; + + /** + * 系统 + */ + @ApiModelProperty("系统") + private String os; + + /** + * 系统版本 + */ + @ApiModelProperty("系统版本") + private String osVersion; + + /** + * 设备 + */ + @ApiModelProperty("设备") + private String model; + + /** + * IP + */ + @ApiModelProperty("IP") + private String clientIp; + + /** + * 客户端时间 + */ + @ApiModelProperty("客户端时间") + private Date clientTime; + + /** + * 创建时间 + */ + @ApiModelProperty("创建时间") + private Date createTime; + + /** + * 更新时间 + */ + @ApiModelProperty("更新时间") + private Date updateTime; + +} diff --git a/accompany-business/accompany-business-service/pom.xml b/accompany-business/accompany-business-service/pom.xml index 4dc5461e3..36c871d7c 100644 --- a/accompany-business/accompany-business-service/pom.xml +++ b/accompany-business/accompany-business-service/pom.xml @@ -88,6 +88,12 @@ org.springframework.boot spring-boot-test-autoconfigure + + + eu.bitwalker + UserAgentUtils + ${bitwalker.version} + \ No newline at end of file diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/link/ShortLinkMapper.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/link/ShortLinkMapper.java new file mode 100644 index 000000000..27d3b36d1 --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/link/ShortLinkMapper.java @@ -0,0 +1,12 @@ +package com.accompany.business.mybatismapper.link; + +import com.accompany.business.model.link.ShortLink; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @author: liaozetao + * @date: 2023/9/19 15:26 + * @description: + */ +public interface ShortLinkMapper extends BaseMapper { +} diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/link/ShortLinkRecordMapper.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/link/ShortLinkRecordMapper.java new file mode 100644 index 000000000..12d169d3b --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/mybatismapper/link/ShortLinkRecordMapper.java @@ -0,0 +1,21 @@ +package com.accompany.business.mybatismapper.link; + +import com.accompany.business.model.link.ShortLinkRecord; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +/** + * @author: liaozetao + * @date: 2023/9/19 15:26 + * @description: + */ +public interface ShortLinkRecordMapper extends BaseMapper { + + /** + * 获取uv数 + * @param linkId + * @return + */ + Integer getUvCount(@Param("linkId") Long linkId); + +} diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/link/ShortLinkRecordService.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/link/ShortLinkRecordService.java new file mode 100644 index 000000000..48379e1a1 --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/link/ShortLinkRecordService.java @@ -0,0 +1,12 @@ +package com.accompany.business.service.link; + +import com.accompany.business.model.link.ShortLinkRecord; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * @author: liaozetao + * @date: 2023/9/19 15:27 + * @description: + */ +public interface ShortLinkRecordService extends IService { +} diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/link/ShortLinkService.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/link/ShortLinkService.java new file mode 100644 index 000000000..a8170d5e4 --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/link/ShortLinkService.java @@ -0,0 +1,20 @@ +package com.accompany.business.service.link; + +import com.accompany.business.model.link.ShortLink; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * @author: liaozetao + * @date: 2023/9/19 15:27 + * @description: + */ +public interface ShortLinkService extends IService { + + /** + * 点击 + * @param code + * @param clientTime + */ + Integer click(String code, String clientTime); + +} diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/link/impl/ShortLinkRecordServiceImpl.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/link/impl/ShortLinkRecordServiceImpl.java new file mode 100644 index 000000000..30cce0182 --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/link/impl/ShortLinkRecordServiceImpl.java @@ -0,0 +1,18 @@ +package com.accompany.business.service.link.impl; + +import com.accompany.business.model.link.ShortLinkRecord; +import com.accompany.business.mybatismapper.link.ShortLinkRecordMapper; +import com.accompany.business.service.link.ShortLinkRecordService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * @author: liaozetao + * @date: 2023/9/19 15:28 + * @description: + */ +@Slf4j +@Service +public class ShortLinkRecordServiceImpl extends ServiceImpl implements ShortLinkRecordService { +} diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/link/impl/ShortLinkServiceImpl.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/link/impl/ShortLinkServiceImpl.java new file mode 100644 index 000000000..7a8ad2b82 --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/link/impl/ShortLinkServiceImpl.java @@ -0,0 +1,100 @@ +package com.accompany.business.service.link.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.util.StrUtil; +import com.accompany.business.enums.link.ShortLinkTypeEnum; +import com.accompany.business.model.link.ShortLink; +import com.accompany.business.model.link.ShortLinkRecord; +import com.accompany.business.mybatismapper.link.ShortLinkMapper; +import com.accompany.business.mybatismapper.link.ShortLinkRecordMapper; +import com.accompany.business.service.link.ShortLinkService; +import com.accompany.common.utils.DateTimeUtil; +import com.accompany.common.utils.IPUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import eu.bitwalker.useragentutils.Browser; +import eu.bitwalker.useragentutils.OperatingSystem; +import eu.bitwalker.useragentutils.UserAgent; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Service; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.util.Date; +import java.util.List; + +/** + * @author: liaozetao + * @date: 2023/9/19 15:28 + * @description: + */ +@Slf4j +@Service +public class ShortLinkServiceImpl extends ServiceImpl implements ShortLinkService { + + @Autowired + private ShortLinkRecordMapper shortLinkRecordMapper; + + @Override + public Integer click(String code, String clientTimeStr) { + int shortLinkType = ShortLinkTypeEnum.CUSTOM.ordinal(); + try { + Long linkId = null; + List shortLinks = baseMapper.selectList(Wrappers.lambdaQuery() + .eq(ShortLink::getCode, code)); + if (CollectionUtil.isNotEmpty(shortLinks)) { + ShortLink shortLink = shortLinks.get(0); + linkId = shortLink.getId(); + shortLinkType = shortLink.getType(); + } + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes == null) { + return shortLinkType; + } + ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes; + HttpServletRequest request = servletRequestAttributes.getRequest(); + String os = StrUtil.EMPTY; + String osVersion = StrUtil.EMPTY; + String model = StrUtil.EMPTY; + //设备 + String userAgentStr = request.getHeader(HttpHeaders.USER_AGENT); + if (StrUtil.isNotEmpty(userAgentStr)) { + UserAgent userAgent = UserAgent.parseUserAgentString(userAgentStr); + OperatingSystem operatingSystem = userAgent.getOperatingSystem(); + os = operatingSystem.getName(); + osVersion = String.valueOf(operatingSystem.getId()); + model = operatingSystem.getDeviceType().getName(); + } + //客户端时间 + Date clientTime = new Date(); + if (StrUtil.isNotEmpty(clientTimeStr)) { + try { + clientTime = DateTimeUtil.convertStrToDate(clientTimeStr, DatePattern.NORM_DATETIME_PATTERN); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + //IP + String ipAddress = IPUtils.getRealIpAddress(request); + //记录 + ShortLinkRecord record = new ShortLinkRecord(); + record.setLinkId(linkId); + record.setClientIp(ipAddress); + record.setOs(os); + record.setOsVersion(osVersion); + record.setModel(model); + record.setClientTime(clientTime); + record.setCreateTime(new Date()); + record.setUpdateTime(new Date()); + shortLinkRecordMapper.insert(record); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return shortLinkType; + } +} diff --git a/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/ShortLinkMapper.xml b/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/ShortLinkMapper.xml new file mode 100644 index 000000000..98181d388 --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/ShortLinkMapper.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/ShortLinkRecordMapper.xml b/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/ShortLinkRecordMapper.xml new file mode 100644 index 000000000..c80c8c59e --- /dev/null +++ b/accompany-business/accompany-business-service/src/main/resources/accompany/sqlmappers/ShortLinkRecordMapper.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/link/ShortLinkController.java b/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/link/ShortLinkController.java new file mode 100644 index 000000000..9078fe18e --- /dev/null +++ b/accompany-business/accompany-business-web/src/main/java/com/accompany/business/controller/link/ShortLinkController.java @@ -0,0 +1,35 @@ +package com.accompany.business.controller.link; + +import com.accompany.business.service.link.ShortLinkService; +import com.accompany.common.result.BusiResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author: liaozetao + * @date: 2023/9/19 19:00 + * @description: + */ +@Api(tags = "短链") +@RestController +@RequestMapping("/short/link") +public class ShortLinkController { + + @Autowired + private ShortLinkService shortLinkService; + + /** + * 点击 + * @return + */ + @ApiOperation("点击") + @GetMapping("click") + public BusiResult click(String code, String clientTime) { + shortLinkService.click(code, clientTime); + return BusiResult.success(); + } +} diff --git a/accompany-dependencies/pom.xml b/accompany-dependencies/pom.xml index 3a1063d10..d986e5206 100644 --- a/accompany-dependencies/pom.xml +++ b/accompany-dependencies/pom.xml @@ -97,6 +97,8 @@ 1.5.0 0.0.20131108.vaadin1 1.64 + 3.2.0 + 1.20