wucl 2 rokov pred
rodič
commit
b1adc9ea61
22 zmenil súbory, kde vykonal 1119 pridanie a 9 odobranie
  1. 200 0
      biz-base/src/main/java/com/dayou/controller/GisUserController.java
  2. 96 0
      biz-base/src/main/java/com/dayou/controller/GisVisitedController.java
  3. 17 0
      common/src/main/java/com/dayou/configuration/CacheConfig.java
  4. 2 2
      common/src/main/java/com/dayou/configuration/WebConfig.java
  5. 2 0
      common/src/main/java/com/dayou/constants/JwtConstants.java
  6. 4 0
      common/src/main/java/com/dayou/exception/ErrorCode.java
  7. 22 6
      common/src/main/java/com/dayou/interceptor/LoginInterceptor.java
  8. 82 0
      common/src/main/java/com/dayou/utils/ImageCode.java
  9. 33 1
      common/src/main/java/com/dayou/utils/IpUtils.java
  10. 12 0
      common/src/main/java/com/dayou/utils/JwtTokenUtil.java
  11. 16 0
      dao/src/main/java/com/dayou/mapper/GisUserMapper.java
  12. 16 0
      dao/src/main/java/com/dayou/mapper/GisVisitedMapper.java
  13. 32 0
      dao/src/main/resources/mapper/GisUserMapper.xml
  14. 25 0
      dao/src/main/resources/mapper/GisVisitedMapper.xml
  15. 2 0
      domain/src/main/java/com/dayou/common/Constants.java
  16. 29 0
      domain/src/main/java/com/dayou/condition/GisLoginCondition.java
  17. 95 0
      domain/src/main/java/com/dayou/entity/GisUser.java
  18. 45 0
      domain/src/main/java/com/dayou/entity/GisVisited.java
  19. 43 0
      service/src/main/java/com/dayou/service/IGisUserService.java
  20. 31 0
      service/src/main/java/com/dayou/service/IGisVisitedService.java
  21. 228 0
      service/src/main/java/com/dayou/service/impl/GisUserServiceImpl.java
  22. 87 0
      service/src/main/java/com/dayou/service/impl/GisVisitedServiceImpl.java

+ 200 - 0
biz-base/src/main/java/com/dayou/controller/GisUserController.java

@@ -0,0 +1,200 @@
+package com.dayou.controller;
+
+import com.dayou.annotation.IgnoreAuth;
+import com.dayou.annotation.OperLog;
+import com.dayou.bo.LoginCacheUserBO;
+import com.dayou.condition.GisLoginCondition;
+import com.dayou.condition.LoginCondition;
+import com.dayou.configuration.CacheConfig;
+import com.dayou.dto.LoginDTO;
+import com.dayou.dto.UpdatePasswordDTO;
+import com.dayou.dto.UserBaseDetailDTO;
+import com.dayou.enums.OperationTypeEnum;
+import com.dayou.utils.ImageCode;
+import com.google.common.cache.Cache;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.web.bind.annotation.RequestMapping;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.web.bind.annotation.RestController;
+import com.dayou.controller.BaseController;
+import com.dayou.service.IGisUserService;
+import com.dayou.entity.GisUser;
+import com.dayou.common.RestResponse;
+import org.springframework.web.bind.annotation.*;
+import com.dayou.common.PullDownModel;
+import com.dayou.utils.ConvertUtil;
+import com.dayou.utils.HttpKit;
+import com.dayou.exception.ErrorCode;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.springframework.http.MediaType;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+
+import static com.dayou.constants.JwtConstants.REST_TOKEN;
+
+/**
+ * GIS用户
+ *
+ * @author wucl
+ * @since 2023-05-17
+ */
+@RestController
+@RequestMapping("gisUser")
+@Slf4j
+public class GisUserController extends BaseController {
+    @Autowired
+    private IGisUserService gisUserService;
+
+    @Autowired
+    @Qualifier("verificationCodeCache")
+    private Cache<String, String> cache;
+
+    /**
+    * GIS用户列表
+    */
+    @GetMapping("")
+    public RestResponse<Page<GisUser>> page(GisUser gisUser, Page page){
+        Page<GisUser> pages=gisUserService.selectPage(page,gisUser);
+        return RestResponse.data(pages);
+    }
+
+    /**
+     * GIS用户详情
+     */
+    @GetMapping("/{id}")
+    public RestResponse<GisUser> detail(@PathVariable Long id){
+        GisUser xGisUser =gisUserService.detail(id);
+        return RestResponse.data(xGisUser);
+     }
+
+    /**
+     * GIS用户新增
+     */
+    @PostMapping("")
+    public RestResponse<Boolean> save(@RequestBody GisUser gisUser) {
+        Boolean ret = gisUserService.add(gisUser);
+        return RestResponse.data(ret);
+    }
+
+    /**
+     * GIS用户更新
+     */
+    @PutMapping("")
+    public RestResponse<Boolean> update(@RequestBody GisUser gisUser) {
+        Boolean ret = gisUserService.update(gisUser);
+        return RestResponse.data(ret);
+    }
+
+    /**
+     * GIS用户删除
+     */
+    @DeleteMapping("/{id}")
+    public RestResponse<Boolean> delete(@PathVariable Long id) {
+        Boolean ret = gisUserService.delete(id);
+        return RestResponse.data(ret);
+    }
+
+
+    /**
+     * GIS用户下拉列表
+     */
+    @GetMapping("/simpleAll")
+    public RestResponse<List<PullDownModel>> simpleAll(){
+        LambdaQueryWrapper<GisUser> lambdaQueryWrapper = new LambdaQueryWrapper<GisUser>()
+        .select(GisUser::getId,GisUser::getName)
+        .eq(GisUser::getDeleted,false);
+        List<GisUser> list= gisUserService.list(lambdaQueryWrapper);
+        List<PullDownModel> ret=ConvertUtil.copyList(list, PullDownModel.class);
+        return RestResponse.data(ret);
+    }
+
+    /**
+     * 生成登录验证码
+     * @return
+     */
+    @IgnoreAuth
+    @GetMapping("/verification")
+    public void genVerificationCode(HttpServletResponse response,String nonceId) {
+        ImageCode imageCode = ImageCode.getInstance();
+        //获取验证码内容
+        String code = imageCode.getCode();
+        //存放到缓存
+        cache.put(nonceId,code);
+        //获取图片
+        ByteArrayInputStream image = imageCode.getImage();
+        //设置内容类型
+        response.setContentType("image/jpg");
+        byte[] bytes = new byte[1024];
+        try (ServletOutputStream outputStream = response.getOutputStream()) {
+            while (image.read(bytes) != -1) {
+                outputStream.write(bytes);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 登录
+     *
+     * @param gisLoginCondition
+     * @return
+     */
+    @PostMapping("/login")
+    @OperLog(title = "GIS登录", businessType = OperationTypeEnum.LOGIN)
+    public RestResponse<LoginDTO> login(@RequestBody @Valid GisLoginCondition gisLoginCondition) {
+        LoginDTO loginDTO = gisUserService.login(gisLoginCondition);
+        return RestResponse.data(loginDTO);
+    }
+
+    /**
+     * 根据token获取基本信息
+     *
+     * @return
+     */
+    @GetMapping("/baseInfo")
+    public RestResponse<GisUser> baseInfo() {
+        String token = HttpKit.getHeaderValue(REST_TOKEN);
+        GisUser gisUser = gisUserService.baseInfo(token);
+        return RestResponse.data(gisUser);
+    }
+
+    /**
+     * 心跳监测
+     * @return
+     */
+    @PostMapping("/keepAlive")
+    public RestResponse<Boolean> isAlive(){
+        String token = HttpKit.getHeaderValue(REST_TOKEN);
+        Boolean alive = gisUserService.isAlive(token);
+        return RestResponse.data(alive);
+    }
+
+    /**
+     * 修改密码
+     * @param passwordDTO
+     * @return
+     */
+    @OperLog(title = "修改密码",businessType = OperationTypeEnum.SET)
+    @PutMapping("/updatePassword")
+    public RestResponse<Boolean> updatePassword(@RequestBody UpdatePasswordDTO passwordDTO){
+        String token = HttpKit.getHeaderValue(REST_TOKEN);
+        Boolean result = gisUserService.updatePassword(passwordDTO,token);
+        return RestResponse.data(result);
+    }
+
+}
+

+ 96 - 0
biz-base/src/main/java/com/dayou/controller/GisVisitedController.java

@@ -0,0 +1,96 @@
+package com.dayou.controller;
+
+import com.dayou.annotation.IgnoreAuth;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.web.bind.annotation.RestController;
+import com.dayou.controller.BaseController;
+import com.dayou.service.IGisVisitedService;
+import com.dayou.entity.GisVisited;
+import com.dayou.common.RestResponse;
+import org.springframework.web.bind.annotation.*;
+import com.dayou.utils.ConvertUtil;
+import com.dayou.utils.HttpKit;
+import com.dayou.exception.ErrorCode;
+import java.util.Date;
+import java.util.List;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.springframework.http.MediaType;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * GIS访问记录
+ *
+ * @author wucl
+ * @since 2023-05-19
+ */
+@RestController
+@RequestMapping("gisVisited")
+@Slf4j
+public class GisVisitedController extends BaseController {
+    @Autowired
+    private IGisVisitedService gisVisitedService;
+
+    /**
+    * GIS访问记录列表
+    */
+    @GetMapping("")
+    public RestResponse<Page<GisVisited>> page(GisVisited gisVisited, Page page){
+        Page<GisVisited> pages=gisVisitedService.selectPage(page,gisVisited);
+        return RestResponse.data(pages);
+    }
+
+    /**
+     * GIS访问记录详情
+     */
+    @GetMapping("/{id}")
+    public RestResponse<GisVisited> detail(@PathVariable Long id){
+        GisVisited xGisVisited =gisVisitedService.detail(id);
+        return RestResponse.data(xGisVisited);
+     }
+
+    /**
+     * GIS访问记录新增
+     */
+    @PostMapping("")
+    public void save(HttpServletRequest request) {
+        gisVisitedService.add(request);
+    }
+
+    /**
+     * GIS访问记录更新
+     */
+    @PutMapping("")
+    public RestResponse<Boolean> update(@RequestBody GisVisited gisVisited) {
+        Boolean ret = gisVisitedService.update(gisVisited);
+        return RestResponse.data(ret);
+    }
+
+    /**
+     * GIS访问记录删除
+     */
+    @DeleteMapping("/{id}")
+    public RestResponse<Boolean> delete(@PathVariable Long id) {
+        Boolean ret = gisVisitedService.delete(id);
+        return RestResponse.data(ret);
+    }
+
+    /**
+     * 访问计数
+     * @return
+     */
+    @IgnoreAuth
+    @GetMapping("/count")
+    public RestResponse<Integer> countTotal(){
+        int count = gisVisitedService.count();
+        return RestResponse.data(count);
+    }
+
+}
+

+ 17 - 0
common/src/main/java/com/dayou/configuration/CacheConfig.java

@@ -1,6 +1,7 @@
 package com.dayou.configuration;
 
 import com.dayou.constants.JwtConstants;
+import com.dayou.entity.GisUser;
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
 import com.dayou.bo.ChatCacheSessionBO;
@@ -133,5 +134,21 @@ public class CacheConfig {
         return cache;
     }
 
+    @Bean
+    @Qualifier("verificationCodeCache")
+    public Cache<String,String> verificationCodeCache(){
+        Cache<String, String> cache = CacheBuilder.newBuilder()
+                .expireAfterAccess(1, TimeUnit.MINUTES)
+                .build();
+        return cache;
+    }
+
+    @Bean
+    @Qualifier("gisLoginCache")
+    public Cache<String, GisUser> gisLoginCache() {
+        Cache<String, GisUser> cache = CacheBuilder.newBuilder()
+                .expireAfterAccess(JwtConstants.GIS_EXPIRATION, TimeUnit.SECONDS).build();
+        return cache;
+    }
 }
 

+ 2 - 2
common/src/main/java/com/dayou/configuration/WebConfig.java

@@ -68,8 +68,8 @@ public class WebConfig implements WebMvcConfigurer {
                 .addPathPatterns("/**")
                 .excludePathPatterns("/*/dfs/**")
                 .excludePathPatterns("/dfs/**")
-                .excludePathPatterns("/user/login", "/oauth/login", "/unified-auth/login",
-                        "/doc/**", "/globalConfig/getSysCfg", "/sdk/**", "/error", "/profession/detail","/callback/**");
+                .excludePathPatterns("/user/login", "/gisUser/login", "/gisUser/verification",
+                        "/gisVisited", "/globalConfig/getSysCfg", "/sdk/**", "/error");
 
         registry.addInterceptor(permissionInterceptor)
                 .addPathPatterns("/**")

+ 2 - 0
common/src/main/java/com/dayou/constants/JwtConstants.java

@@ -26,4 +26,6 @@ public interface JwtConstants {
 
     String USER_TYPE_CLAIM_KEY="userType";
 
+    //30分钟
+    Long GIS_EXPIRATION = 60*30L;
 }

+ 4 - 0
common/src/main/java/com/dayou/exception/ErrorCode.java

@@ -47,6 +47,10 @@ public class ErrorCode {
 
     public static final ErrorCode ITEM_EVALUATE_ERROR = ErrorCode("10021", "抱歉!当前项目还未完成,暂时无法评价。");
 
+    public static final ErrorCode GIS_USER_EXPIRY = ErrorCode("10022", "抱歉!该账号已过期,请联系管理员。");
+
+    public static final ErrorCode GIS_USER_DISABLE = ErrorCode("10023", "抱歉!该账号已被禁用,请联系管理员。");
+
 
 
 

+ 22 - 6
common/src/main/java/com/dayou/interceptor/LoginInterceptor.java

@@ -1,6 +1,7 @@
 package com.dayou.interceptor;
 
 import com.dayou.annotation.IgnoreAuth;
+import com.dayou.entity.GisUser;
 import com.google.common.cache.Cache;
 import com.dayou.bo.LoginCacheUserBO;
 import com.dayou.constants.JwtConstants;
@@ -24,6 +25,8 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.text.MessageFormat;
 
+import static com.dayou.common.Constants.GIS_USER;
+
 @Component
 @Slf4j
 public class LoginInterceptor implements HandlerInterceptor {
@@ -32,6 +35,11 @@ public class LoginInterceptor implements HandlerInterceptor {
     @Autowired
     @Qualifier("loginCache")
     private Cache<Long, LoginCacheUserBO> loginCache;
+
+    @Autowired
+    @Qualifier("gisLoginCache")
+    private Cache<String, GisUser> gisLoginCache;
+
     @Autowired
     @Qualifier("noExpireCache")
     private Cache<String, Object> noExpireCache;
@@ -53,13 +61,21 @@ public class LoginInterceptor implements HandlerInterceptor {
         try {
             if (StringUtils.isNotBlank(token)) {
                 Claims claims = JwtTokenUtil.getClaimFromToken(token, JwtConstants.SECRET);
-                Long userId = Long.valueOf(claims.getSubject());
-                loginCacheUserBO = loginCache.getIfPresent(userId);
-                if (loginCacheUserBO == null) {
-                    ErrorCode.throwBusinessException(ErrorCode.LOGIN_EXPIRE);
+                String subject = claims.getSubject();
+                if (subject.startsWith(GIS_USER)){
+                    GisUser gisUser = gisLoginCache.getIfPresent(subject);
+                    if (gisUser == null) {
+                        ErrorCode.throwBusinessException(ErrorCode.LOGIN_EXPIRE);
+                    }
+                }else{
+                    Long userId = Long.valueOf(subject);
+                    loginCacheUserBO = loginCache.getIfPresent(userId);
+                    if (loginCacheUserBO == null) {
+                        ErrorCode.throwBusinessException(ErrorCode.LOGIN_EXPIRE);
+                    }
+                    LoginContext.setLoginCacheUserBO(loginCacheUserBO);
+                    PermissionContext.setFlag(Boolean.FALSE);
                 }
-                LoginContext.setLoginCacheUserBO(loginCacheUserBO);
-                PermissionContext.setFlag(Boolean.FALSE);
             }
         } catch (ExpiredJwtException ee) {
             //判断token是否过期

+ 82 - 0
common/src/main/java/com/dayou/utils/ImageCode.java

@@ -0,0 +1,82 @@
+package com.dayou.utils;
+
+import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
+import lombok.Data;
+
+import javax.imageio.ImageIO;
+import javax.imageio.stream.ImageOutputStream;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Random;
+
+/**
+ * 类说明:
+ *
+ * @author: wucl
+ * @since: 2023/5/17
+ * created with IntelliJ IDEA.
+ */
+@Data
+public class ImageCode {
+    //图形内容
+    public String code;
+    //图片
+    public ByteArrayInputStream image;
+    //宽
+    private int wight = 400;
+    //高
+    private int height = 100;
+
+    public static ImageCode getInstance() {
+        return new ImageCode();
+    }
+
+    public ImageCode() {
+        //图形缓冲区
+        BufferedImage image = new BufferedImage(wight, height, BufferedImage.TYPE_3BYTE_BGR);
+        //画笔
+        Graphics graphics = image.getGraphics();
+        //设置颜色
+        graphics.setColor(new Color(232, 240, 254));
+        //画矩形
+        graphics.fillRect(0, 0, wight, height);
+        //设置字体
+        graphics.setFont(new Font("宋体", Font.PLAIN, 60));
+        //设置随机数
+        Random random = new Random();
+        //算数验证码
+        int num1 = random.nextInt(20);
+        int num2 = random.nextInt(20);
+        //设置颜色
+        graphics.setColor(new Color(2, 0, 0));
+        //画图
+        int Y = 60;
+        graphics.drawString(String.valueOf(num1), wight / 6 * 0 + 50, Y);
+        graphics.drawString("+", wight / 6 * 1 + 50, Y);
+        graphics.drawString(String.valueOf(num2), wight / 6 * 2 + 50, Y);
+        graphics.drawString("=", wight / 6 * 3 + 50, Y);
+        graphics.drawString("?", wight / 6 * 4 + 50, Y);
+        //计算值
+        int result = num1 + num2;
+        this.code = result + "";
+        //收笔
+        graphics.dispose();
+
+        ByteArrayInputStream inputStream = null;
+        ByteOutputStream outputStream = new ByteOutputStream();
+
+        //赋值给ByteArrayInputStream
+        try {
+            ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
+            ImageIO.write(image, "jpg", imageOutputStream);
+
+            inputStream = new ByteArrayInputStream(outputStream.toByteArray());
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        //生成图片
+        this.image = inputStream;
+    }
+}

+ 33 - 1
common/src/main/java/com/dayou/utils/IpUtils.java

@@ -1,9 +1,19 @@
 package com.dayou.utils;
 
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+
 import javax.servlet.http.HttpServletRequest;
+import javax.xml.transform.Result;
+import java.io.*;
 import java.net.*;
+import java.nio.charset.Charset;
 import java.text.MessageFormat;
 import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -12,6 +22,8 @@ import java.util.Objects;
  * @author ruoyi
  */
 public class IpUtils {
+
+    private static final String QUERY_URL = "http://whois.pconline.com.cn/ipJson.jsp";
     public static String getIpAddr(HttpServletRequest request) {
         if (request == null) {
             return "unknown";
@@ -190,7 +202,27 @@ public class IpUtils {
         return "未知";
     }
 
+    /**
+     *
+     * @param ip
+     * @return
+     * @throws UnsupportedEncodingException
+     */
+    public static JSONObject getAddresses(String ip) {
+        // 这里调用pconline的接口
+        try {
+            Map<String,Object> params = new HashMap<>();
+            params.put("json",true);
+            params.put("ip",ip);
+            String result = HttpUtil.get(QUERY_URL,params,1000);
+            JSONObject jsonObject = JSON.parseObject(result);
+            return jsonObject;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
     public static void main(String[] args) {
-        System.out.println(getHostIp());
+        JSONObject addresses = getAddresses("220.165.249.18");
     }
 }

+ 12 - 0
common/src/main/java/com/dayou/utils/JwtTokenUtil.java

@@ -140,6 +140,18 @@ public class JwtTokenUtil {
                 .compact();
     }
 
+    public static String doGenerateGisToken(Map<String, Object> claims, String subject) {
+        final Date createdDate = new Date();
+        final Date expirationDate = new Date(createdDate.getTime() + JwtConstants.GIS_EXPIRATION * 1000);
+
+        return Jwts.builder()
+                .setClaims(claims)
+                .setSubject(subject)
+                .setIssuedAt(createdDate)
+                .setExpiration(expirationDate)
+                .signWith(SignatureAlgorithm.HS512, JwtConstants.SECRET)
+                .compact();
+    }
     /**
      * 生成token
      */

+ 16 - 0
dao/src/main/java/com/dayou/mapper/GisUserMapper.java

@@ -0,0 +1,16 @@
+package com.dayou.mapper;
+
+import com.dayou.entity.GisUser;
+import com.dayou.dao.CustomBaseMapper;
+
+/**
+ * <p>
+ * GIS用户 Mapper 接口
+ * </p>
+ *
+ * @author wucl
+ * @since 2023-05-17
+ */
+public interface GisUserMapper extends CustomBaseMapper<GisUser> {
+
+}

+ 16 - 0
dao/src/main/java/com/dayou/mapper/GisVisitedMapper.java

@@ -0,0 +1,16 @@
+package com.dayou.mapper;
+
+import com.dayou.entity.GisVisited;
+import com.dayou.dao.CustomBaseMapper;
+
+/**
+ * <p>
+ * GIS访问记录 Mapper 接口
+ * </p>
+ *
+ * @author wucl
+ * @since 2023-05-19
+ */
+public interface GisVisitedMapper extends CustomBaseMapper<GisVisited> {
+
+}

+ 32 - 0
dao/src/main/resources/mapper/GisUserMapper.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.dayou.mapper.GisUserMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.dayou.entity.GisUser">
+        <result column="id" property="id" />
+        <result column="deleted" property="deleted" />
+        <result column="created" property="created" />
+        <result column="modified" property="modified" />
+        <result column="name" property="name" />
+        <result column="city_name" property="cityName" />
+        <result column="country_name" property="countryName" />
+        <result column="account" property="account" />
+        <result column="password" property="password" />
+        <result column="linkman" property="linkman" />
+        <result column="mobile" property="mobile" />
+        <result column="email" property="email" />
+        <result column="expiry_date" property="expiryDate" />
+        <result column="enable" property="enable" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id,
+        deleted,
+        created,
+        modified,
+        name, city_name, country_name, account, password, linkman, mobile, email, expiry_date, enable
+    </sql>
+
+</mapper>

+ 25 - 0
dao/src/main/resources/mapper/GisVisitedMapper.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.dayou.mapper.GisVisitedMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.dayou.entity.GisVisited">
+        <result column="id" property="id" />
+        <result column="deleted" property="deleted" />
+        <result column="created" property="created" />
+        <result column="modified" property="modified" />
+        <result column="remote_ip" property="remoteIp" />
+        <result column="remote_host" property="remoteHost" />
+        <result column="remote_addr" property="remoteAddr" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id,
+        deleted,
+        created,
+        modified,
+        remote_ip, remote_host, remote_addr
+    </sql>
+
+</mapper>

+ 2 - 0
domain/src/main/java/com/dayou/common/Constants.java

@@ -90,4 +90,6 @@ public interface Constants {
     String SUPERVISOR = "营销主管";
 
     String MARKET_MANAGER = "市场部经理";
+
+    String GIS_USER= "GIS";
 }

+ 29 - 0
domain/src/main/java/com/dayou/condition/GisLoginCondition.java

@@ -0,0 +1,29 @@
+package com.dayou.condition;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.NotEmpty;
+
+/**
+ * 类说明:
+ *
+ * @author: wucl
+ * @since: 2023/5/17
+ * created with IntelliJ IDEA.
+ */
+@Data
+public class GisLoginCondition {
+
+    @NotEmpty(message = "账号不能为空")
+    private String account;
+
+    @NotEmpty(message = "密码不能为空")
+    private String password;
+
+    /**
+     * 随机字符
+     */
+    private String  nonceId;
+
+    @NotEmpty(message = "验证码不能为空")
+    private String verificationCode;
+}

+ 95 - 0
domain/src/main/java/com/dayou/entity/GisUser.java

@@ -0,0 +1,95 @@
+package com.dayou.entity;
+import com.dayou.common.BaseEntity;
+import java.time.LocalDate;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import com.dayou.annotation.ExcelSheet;
+import com.dayou.annotation.ExportCell;
+import com.dayou.annotation.ImportCell;
+/**
+ * <p>
+ * GIS用户
+ * </p>
+ *
+ * @author wucl
+ * @since 2023-05-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ExcelSheet(sheetName = "GIS用户")
+public class GisUser extends BaseEntity {
+
+    private static final long serialVersionUID=1L;
+
+    /**
+     * 用户名称
+     */
+    @ImportCell
+    @ExportCell(columnName = "用户名称")
+    private String name;
+
+    /**
+     * 州市
+     */
+    @ImportCell
+    @ExportCell(columnName = "州市")
+    private String cityName;
+
+    /**
+     * 县市区
+     */
+    @ImportCell
+    @ExportCell(columnName = "县市区")
+    private String countryName;
+
+    /**
+     * 账号
+     */
+    @ImportCell
+    @ExportCell(columnName = "账号")
+    private String account;
+
+    /**
+     * 密码
+     */
+    @ImportCell
+    @ExportCell(columnName = "密码")
+    private String password;
+
+    /**
+     * 联系人
+     */
+    @ImportCell
+    @ExportCell(columnName = "联系人")
+    private String linkman;
+
+    /**
+     * 联系电话
+     */
+    @ImportCell
+    @ExportCell(columnName = "联系电话")
+    private String mobile;
+
+    /**
+     * 邮箱
+     */
+    @ImportCell
+    @ExportCell(columnName = "邮箱")
+    private String email;
+
+    /**
+     * 有效期
+     */
+    @ImportCell
+    @ExportCell(columnName = "有效期")
+    private LocalDate expiryDate;
+
+    /**
+     * 激活状态
+     */
+    @ImportCell
+    @ExportCell(columnName = "激活状态")
+    private Boolean enable;
+
+
+}

+ 45 - 0
domain/src/main/java/com/dayou/entity/GisVisited.java

@@ -0,0 +1,45 @@
+package com.dayou.entity;
+import com.dayou.common.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import com.dayou.annotation.ExcelSheet;
+import com.dayou.annotation.ExportCell;
+import com.dayou.annotation.ImportCell;
+/**
+ * <p>
+ * GIS访问记录
+ * </p>
+ *
+ * @author wucl
+ * @since 2023-05-19
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ExcelSheet(sheetName = "GIS访问记录")
+public class GisVisited extends BaseEntity {
+
+    private static final long serialVersionUID=1L;
+
+    /**
+     * 访问IP
+     */
+    @ImportCell
+    @ExportCell(columnName = "访问IP")
+    private String remoteIp;
+
+    /**
+     * 主机名
+     */
+    @ImportCell
+    @ExportCell(columnName = "主机名")
+    private String remoteHost;
+
+    /**
+     * 远程地址
+     */
+    @ImportCell
+    @ExportCell(columnName = "远程地址")
+    private String remoteAddr;
+
+
+}

+ 43 - 0
service/src/main/java/com/dayou/service/IGisUserService.java

@@ -0,0 +1,43 @@
+package com.dayou.service;
+import com.dayou.condition.GisLoginCondition;
+import com.dayou.condition.LoginCondition;
+import com.dayou.dto.LoginDTO;
+import com.dayou.dto.UpdatePasswordDTO;
+import com.dayou.entity.GisUser;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * <p>
+ * GIS用户 服务类
+ * </p>
+ *
+ * @author wucl
+ * @since 2023-05-17
+ */
+public interface IGisUserService extends IService<GisUser> {
+
+        Page<GisUser> selectPage(Page page,GisUser gisUser);
+
+        GisUser detail(Long id);
+
+        Boolean add(GisUser gisUser);
+
+        Boolean update(GisUser gisUser);
+
+        Boolean delete(Long id);
+
+    LoginDTO login(GisLoginCondition gisLoginCondition);
+
+        GisUser baseInfo(String token);
+
+    Boolean isAlive(String token);
+
+
+    Boolean updatePassword(UpdatePasswordDTO passwordDTO,String token);
+}

+ 31 - 0
service/src/main/java/com/dayou/service/IGisVisitedService.java

@@ -0,0 +1,31 @@
+package com.dayou.service;
+import com.dayou.entity.GisVisited;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * <p>
+ * GIS访问记录 服务类
+ * </p>
+ *
+ * @author wucl
+ * @since 2023-05-19
+ */
+public interface IGisVisitedService extends IService<GisVisited> {
+
+        Page<GisVisited> selectPage(Page page,GisVisited gisVisited);
+
+        GisVisited detail(Long id);
+
+        void add(HttpServletRequest request);
+
+        Boolean update(GisVisited gisVisited);
+
+        Boolean delete(Long id);
+
+}

+ 228 - 0
service/src/main/java/com/dayou/service/impl/GisUserServiceImpl.java

@@ -0,0 +1,228 @@
+package com.dayou.service.impl;
+
+import cn.hutool.Hutool;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.dayou.common.BaseEntity;
+import com.dayou.condition.GisLoginCondition;
+import com.dayou.condition.LoginCondition;
+import com.dayou.constants.JwtConstants;
+import com.dayou.dto.LoginDTO;
+import com.dayou.dto.UpdatePasswordDTO;
+import com.dayou.entity.GisUser;
+import com.dayou.entity.GisVisited;
+import com.dayou.entity.User;
+import com.dayou.exception.ErrorCode;
+import com.dayou.mapper.GisUserMapper;
+import com.dayou.service.IGisUserService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.dayou.utils.IpUtils;
+import com.dayou.utils.JwtTokenUtil;
+import com.dayou.utils.LoginContext;
+import com.google.common.cache.Cache;
+import com.google.common.collect.Maps;
+import io.jsonwebtoken.Claims;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Service;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.dayou.utils.ExcelUtil;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.time.LocalDate;
+import java.util.*;
+
+import org.springframework.transaction.annotation.Transactional;
+import com.dayou.enums.BatchTaskTypeEnum;
+
+import javax.servlet.http.HttpServletRequest;
+
+import static com.dayou.common.Constants.GIS_USER;
+import static com.dayou.exception.ErrorCode.*;
+
+/**
+ * <p>
+ * GIS用户 服务实现类
+ * </p>
+ *
+ * @author wucl
+ * @since 2023-05-17
+ */
+@Service
+public class GisUserServiceImpl extends ServiceImpl<GisUserMapper, GisUser> implements IGisUserService {
+
+    @Autowired
+    @Qualifier("verificationCodeCache")
+    private Cache<String,String> cache;
+
+    @Autowired
+    @Qualifier("gisLoginCache")
+    private Cache<String,GisUser> loginCache;
+
+    @Autowired
+    private GisUserMapper gisUserMapper;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Page<GisUser> selectPage(Page page,GisUser gisUser){
+        return this.page(page, new QueryWrapper<GisUser>(gisUser));
+    }
+
+
+    @Override
+    public GisUser detail(Long id){
+        return this.getById(id);
+    }
+
+    @Override
+    public Boolean add(GisUser gisUser){
+        return  this.save(gisUser);
+    }
+
+    @Override
+    public Boolean update(GisUser gisUser){
+        return  this.updateById(gisUser);
+    }
+
+    @Override
+    public Boolean delete(Long id){
+        //逻辑删除
+        return this.removeById(id);
+    }
+
+    @Override
+    public LoginDTO login(GisLoginCondition gisLoginCondition) {
+        doCheckVerificationCode(gisLoginCondition);
+
+        String account = gisLoginCondition.getAccount();
+        String pwd = gisLoginCondition.getPassword();
+
+        GisUser user = doCheckGisUserLogin(account, pwd);
+
+        if (user.getEnable().equals(Boolean.FALSE)) {
+            ErrorCode.throwBusinessException(USER_DISABLE);
+        }
+
+        Long userId = user.getId();
+        String subject = GIS_USER + userId;
+        Map<String, Object> claims = Maps.newHashMap();
+        String token = JwtTokenUtil.doGenerateGisToken(claims,subject);
+        //缓存用户信息
+        cacheGisUser(user);
+
+        return LoginDTO.builder()
+                .token(token)
+                .build();
+    }
+
+    @Override
+    public GisUser baseInfo(String token) {
+        Claims claims = JwtTokenUtil.getClaimFromToken(token, JwtConstants.SECRET);
+        String subject = claims.getSubject();
+        String id = subject.split(GIS_USER)[1];
+        Long gisUserId = Long.valueOf(id);
+        GisUser gisUser = this.getOne(new LambdaQueryWrapper<GisUser>()
+                .select(GisUser::getName,
+                        GisUser::getEnable,
+                        GisUser::getAccount,
+                        GisUser::getCityName,
+                        GisUser::getCountryName,
+                        GisUser::getEmail,
+                        GisUser::getExpiryDate,
+                        GisUser::getLinkman,
+                        GisUser::getMobile).eq(BaseEntity::getId, gisUserId));
+        return gisUser;
+    }
+
+    @Override
+    public Boolean isAlive(String token) {
+        Claims claimFromToken = JwtTokenUtil.getClaimFromToken(token, JwtConstants.SECRET);
+        final Date current = new Date();
+        claimFromToken.setExpiration(new Date((current.getTime() + JwtConstants.GIS_EXPIRATION * 1000)));
+        String subject = claimFromToken.getSubject();
+        loginCache.put(subject,loginCache.getIfPresent(subject));
+        return Boolean.TRUE;
+    }
+
+    @Override
+    public Boolean updatePassword(UpdatePasswordDTO passwordDTO,String token) {
+        Claims claims = JwtTokenUtil.getClaimFromToken(token, JwtConstants.SECRET);
+        String subject = claims.getSubject();
+        String id = subject.split(GIS_USER)[1];
+        Long gisUserId = Long.valueOf(id);
+        GisUser gisUser = this.getById(gisUserId);
+
+        if (!StrUtil.equals(gisUser.getPassword(),passwordDTO.getOriginalPassword())){
+            ErrorCode.throwBusinessException(ErrorCode.PASSWORD_ERROR);
+        }
+
+        if (!StrUtil.equals(passwordDTO.getCurrentPassword(),passwordDTO.getRepeatPassword())){
+            ErrorCode.throwBusinessException(ErrorCode.PASSWORD_DIFFERENT);
+        }
+
+        boolean update = this.update(new LambdaUpdateWrapper<GisUser>()
+                .set(GisUser::getPassword, passwordDTO.getCurrentPassword())
+                .eq(BaseEntity::getId,gisUserId));
+        return update;
+    }
+
+    private GisUser doCheckGisUserLogin(String account, String pwd) {
+        List<GisUser> users = gisUserMapper.selectList(new LambdaQueryWrapper<GisUser>()
+                .eq(GisUser::getAccount,account).eq(BaseEntity::getDeleted,false));
+        if (CollectionUtils.isEmpty(users)){
+            ErrorCode.throwBusinessException(PWD_ERROR);
+        }
+
+        GisUser user = users.get(0);
+        Long userId = user.getId();
+        LambdaQueryWrapper<GisUser> userLambdaQueryWrapper = new LambdaQueryWrapper<GisUser>()
+                .eq(GisUser::getId, userId)
+                .eq(GisUser::getPassword, pwd)
+                .eq(GisUser::getDeleted, false);
+
+        GisUser xUser = this.getOne(userLambdaQueryWrapper);
+
+        if (xUser == null) {
+            ErrorCode.throwBusinessException(PWD_ERROR);
+        }
+        LocalDate now = LocalDate.now();
+        LocalDate expiryDate = xUser.getExpiryDate();
+        if (now.isAfter(expiryDate)){
+            ErrorCode.throwBusinessException(GIS_USER_EXPIRY);
+        }
+        if (!xUser.getEnable()){
+            ErrorCode.throwBusinessException(GIS_USER_DISABLE);
+        }
+
+        return xUser;
+    }
+
+    private void cacheGisUser(GisUser user) {
+        loginCache.put(GIS_USER+user.getId(),user);
+    }
+
+    private void doCheckVerificationCode(GisLoginCondition gisLoginCondition) {
+        Optional.ofNullable(gisLoginCondition.getNonceId()).ifPresent(x->{
+            String code = cache.getIfPresent(x);
+            if (StrUtil.isBlank(code)){
+                ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR,"图形验证码过期,请点击刷新。");
+            }
+            if (!code.equals(gisLoginCondition.getVerificationCode())){
+                ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR,"验证码错误,请重新输入");
+            }
+        });
+
+    }
+}

+ 87 - 0
service/src/main/java/com/dayou/service/impl/GisVisitedServiceImpl.java

@@ -0,0 +1,87 @@
+package com.dayou.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.dayou.entity.GisVisited;
+import com.dayou.mapper.GisVisitedMapper;
+import com.dayou.service.IGisVisitedService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.dayou.utils.IpUtils;
+import com.google.gson.JsonObject;
+import org.apache.commons.compress.utils.Lists;
+import org.springframework.stereotype.Service;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.dayou.utils.ExcelUtil;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.web.multipart.MultipartFile;
+import java.util.List;
+import java.util.ArrayList;
+import org.springframework.transaction.annotation.Transactional;
+import com.dayou.enums.BatchTaskTypeEnum;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * <p>
+ * GIS访问记录 服务实现类
+ * </p>
+ *
+ * @author wucl
+ * @since 2023-05-19
+ */
+@Service
+public class GisVisitedServiceImpl extends ServiceImpl<GisVisitedMapper, GisVisited> implements IGisVisitedService {
+
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Page<GisVisited> selectPage(Page page,GisVisited gisVisited){
+        return this.page(page, new QueryWrapper<GisVisited>(gisVisited));
+    }
+
+
+    @Override
+    public GisVisited detail(Long id){
+        return this.getById(id);
+    }
+
+    @Override
+    public void add(HttpServletRequest request){
+        GisVisited gisVisited = new GisVisited();
+        String ip = IpUtils.getIpAddr(request);
+        gisVisited.setRemoteIp(ip);
+        JSONObject addresses = IpUtils.getAddresses(ip);
+        List<String> host = Lists.newArrayList();
+        if (addresses!=null){
+            host.add((String) addresses.get("pro"));
+            host.add((String) addresses.get("city"));
+            host.add((String) addresses.get("region"));
+            gisVisited.setRemoteAddr((String) addresses.get("addr"));
+        }else {
+            host.add("Unknown");
+            gisVisited.setRemoteAddr("Unknown");
+        }
+        gisVisited.setRemoteHost(host.toString());
+        this.save(gisVisited);
+    }
+
+    @Override
+    public Boolean update(GisVisited gisVisited){
+        return  this.updateById(gisVisited);
+    }
+
+    @Override
+    public Boolean delete(Long id){
+        //逻辑删除
+        return this.removeById(id);
+    }
+}