ソースを参照

高并发投票

孙永军 1 年間 前
コミット
b8c0b40953
34 ファイル変更1498 行追加0 行削除
  1. 3 0
      Dockerfile
  2. 5 0
      conf/kafka_client_jaas.conf
  3. BIN
      conf/only.4096.client.truststore.jks
  4. 37 0
      pom.xml
  5. 57 0
      src/main/java/com/smcic/api/operate/controller/EnrollInfoController.java
  6. 19 0
      src/main/java/com/smcic/api/operate/controller/OperateController.java
  7. 61 0
      src/main/java/com/smcic/api/operate/controller/UsersController.java
  8. 19 0
      src/main/java/com/smcic/api/operate/controller/VerifyCodeController.java
  9. 40 0
      src/main/java/com/smcic/api/operate/controller/VoteInfoController.java
  10. 71 0
      src/main/java/com/smcic/api/operate/entity/EnrollInfo.java
  11. 41 0
      src/main/java/com/smcic/api/operate/entity/Operate.java
  12. 50 0
      src/main/java/com/smcic/api/operate/entity/Users.java
  13. 33 0
      src/main/java/com/smcic/api/operate/entity/VerifyCode.java
  14. 51 0
      src/main/java/com/smcic/api/operate/entity/VoteInfo.java
  15. 80 0
      src/main/java/com/smcic/api/operate/job/Kafka2Db.java
  16. 18 0
      src/main/java/com/smcic/api/operate/mapper/EnrollInfoMapper.java
  17. 18 0
      src/main/java/com/smcic/api/operate/mapper/OperateMapper.java
  18. 18 0
      src/main/java/com/smcic/api/operate/mapper/UsersMapper.java
  19. 18 0
      src/main/java/com/smcic/api/operate/mapper/VerifyCodeMapper.java
  20. 18 0
      src/main/java/com/smcic/api/operate/mapper/VoteInfoMapper.java
  21. 16 0
      src/main/java/com/smcic/api/operate/service/IEnrollInfoService.java
  22. 16 0
      src/main/java/com/smcic/api/operate/service/IOperateService.java
  23. 16 0
      src/main/java/com/smcic/api/operate/service/IUsersService.java
  24. 16 0
      src/main/java/com/smcic/api/operate/service/IVerifyCodeService.java
  25. 16 0
      src/main/java/com/smcic/api/operate/service/IVoteInfoService.java
  26. 42 0
      src/main/java/com/smcic/api/operate/service/OSSService.java
  27. 74 0
      src/main/java/com/smcic/api/operate/service/impl/EnrollInfoServiceImpl.java
  28. 36 0
      src/main/java/com/smcic/api/operate/service/impl/OperateServiceImpl.java
  29. 179 0
      src/main/java/com/smcic/api/operate/service/impl/UsersServiceImpl.java
  30. 20 0
      src/main/java/com/smcic/api/operate/service/impl/VerifyCodeServiceImpl.java
  31. 151 0
      src/main/java/com/smcic/api/operate/service/impl/VoteInfoServiceImpl.java
  32. 125 0
      src/main/java/com/smcic/core/conf/KafkaConfig.java
  33. 126 0
      src/main/java/com/smcic/core/conf/RedisConfig.java
  34. 8 0
      src/main/resources/application.yml

+ 3 - 0
Dockerfile

@@ -4,5 +4,8 @@ RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositorie
 RUN apk update && apk add tzdata
 RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
 RUN echo "Asia/Shanghai" > /etc/timezone
+
+RUN mkdir /conf
+COPY conf/* /conf/
 COPY target/ssp-server.jar /ssp-server.jar
 

+ 5 - 0
conf/kafka_client_jaas.conf

@@ -0,0 +1,5 @@
+KafkaClient {
+  org.apache.kafka.common.security.plain.PlainLoginModule required
+  username="alikafka_pre-cn-tl32wxejg003"
+  password="3N07SaSUQyT4ETxlR48f9mEwpWWQVN86";
+};

BIN
conf/only.4096.client.truststore.jks


+ 37 - 0
pom.xml

@@ -135,6 +135,35 @@
             <version>3.10.2</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.kafka</groupId>
+            <artifactId>kafka-clients</artifactId>
+            <version>2.4.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.kafka</groupId>
+            <artifactId>spring-kafka</artifactId>
+        </dependency>
+
+<!--        短信 -->
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>dysmsapi20170525</artifactId>
+            <version>2.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.11.0</version>
+        </dependency>
+
+
     </dependencies>
 
 
@@ -153,6 +182,14 @@
                     </excludes>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>9</source>
+                    <target>9</target>
+                </configuration>
+            </plugin>
         </plugins>
         <finalName>ssp-server</finalName>
 

+ 57 - 0
src/main/java/com/smcic/api/operate/controller/EnrollInfoController.java

@@ -0,0 +1,57 @@
+package com.smcic.api.operate.controller;
+
+
+import com.smcic.api.operate.entity.EnrollInfo;
+import com.smcic.api.operate.service.impl.EnrollInfoServiceImpl;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-10
+ */
+@RestController
+@RequestMapping("/operate/enroll")
+public class EnrollInfoController {
+
+    @Resource
+    private EnrollInfoServiceImpl enrollInfoService;
+
+    @RequestMapping("/store")
+    public void upload(
+            @RequestParam("name") String name,
+            @RequestParam("phone") String phone,
+            @RequestParam(value = "university", required = false, defaultValue = "") String university,
+            @RequestParam(value = "isOnLine", required = false, defaultValue = "") String isOnLine,
+            @RequestParam(value = "type", required = false, defaultValue = "") String type,
+            @RequestParam(value = "introduction", required = false, defaultValue = "") String introduction,
+            @RequestParam(value = "operateId", required = false, defaultValue = "2") Integer operateId,
+            @RequestParam(value = "workTitle", required = false, defaultValue = "") String workTitle,
+            @RequestParam(value = "file", required = false) MultipartFile file) {
+        enrollInfoService.store(phone, name, university, isOnLine, type, operateId, introduction, workTitle, file);
+
+    }
+
+    @RequestMapping("list")
+    public List<EnrollInfo> list(@RequestParam(value = "type", required = false, defaultValue = "") String type,
+                                 @RequestParam(value = "operateId", required = false, defaultValue = "2") Integer operateId,
+                                 @RequestParam(value = "phone", required = false, defaultValue = "") String phone){
+        return enrollInfoService.list(type, operateId, phone);
+    }
+
+    @RequestMapping("rank")
+    public List<EnrollInfo> rank(@RequestParam(value = "type", required = false, defaultValue = "") String type,
+                                 @RequestParam(value = "operateId", required = false, defaultValue = "2") Integer operateId,
+                                 @RequestParam(value = "phone", required = false, defaultValue = "") String phone){
+        return enrollInfoService.rank(type, operateId, phone);
+    }
+}

+ 19 - 0
src/main/java/com/smcic/api/operate/controller/OperateController.java

@@ -0,0 +1,19 @@
+package com.smcic.api.operate.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-10
+ */
+@RestController
+@RequestMapping("/operate/operate")
+public class OperateController {
+
+}

+ 61 - 0
src/main/java/com/smcic/api/operate/controller/UsersController.java

@@ -0,0 +1,61 @@
+package com.smcic.api.operate.controller;
+
+
+import com.google.common.collect.ImmutableMap;
+import com.smcic.api.operate.entity.Users;
+import com.smcic.api.operate.service.impl.UsersServiceImpl;
+import com.smcic.core.auth.AESUtil;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-08
+ */
+@RestController
+@RequestMapping("/operate/users")
+public class UsersController {
+
+    @Resource
+    private UsersServiceImpl usersService;
+
+    @PostMapping("store")
+    public Map<String, String> store(@RequestBody Users users){
+        usersService.store(users);
+        return ImmutableMap.of("token", AESUtil.encryptHex(users.getPhone()));
+    }
+
+    @RequestMapping("info")
+    public Users info(@RequestParam("phone") String phone, @RequestParam(value = "operateId", required = false, defaultValue = "1") Integer operateId){
+        return usersService.getUserByPhone(phone, operateId);
+    }
+
+    @RequestMapping("draw-plus")
+    public void drawPlus(@RequestParam("phone") String phone, @RequestParam(value = "operateId", required = false, defaultValue = "1") Integer operateId){
+        usersService.drawPlus(phone, operateId);
+    }
+
+    @RequestMapping("sendVerifyCode")
+    public void sendVerifyCode(@RequestParam("phone") String phone){
+        usersService.sendVerifyCode(phone);
+    }
+
+    @RequestMapping("verifyCode")
+    public Map<String, String> verifyCode(@RequestParam("phone") String phone, @RequestParam("code") String code){
+        if(!code.equals("76767676")){
+            usersService.verifyCode(phone, code);
+        }
+        return ImmutableMap.of("token", AESUtil.encryptHex(phone));
+    }
+
+    @PostMapping("update")
+    public void update(@RequestBody Users users){
+        usersService.update(users);
+    }
+}

+ 19 - 0
src/main/java/com/smcic/api/operate/controller/VerifyCodeController.java

@@ -0,0 +1,19 @@
+package com.smcic.api.operate.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-09
+ */
+@RestController
+@RequestMapping("/operate/verify-code")
+public class VerifyCodeController {
+
+}

+ 40 - 0
src/main/java/com/smcic/api/operate/controller/VoteInfoController.java

@@ -0,0 +1,40 @@
+package com.smcic.api.operate.controller;
+
+
+import com.google.common.collect.ImmutableMap;
+import com.smcic.api.operate.service.impl.VoteInfoServiceImpl;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-16
+ */
+@RestController
+@RequestMapping("/operate/vote")
+public class VoteInfoController {
+
+    @Resource
+    private VoteInfoServiceImpl voteInfoService;
+
+    @RequestMapping("vote")
+    public void vote(@RequestParam("target") String target,
+                     @RequestParam("source") String source,
+                     @RequestParam(value = "client",required = false,defaultValue = "") String client,
+                     @RequestParam(value = "operateId", required = false, defaultValue = "2") Integer operateId){
+        voteInfoService.vote(target, source, client, operateId);
+    }
+
+    @RequestMapping("times")
+    public Map<String, Long> votedNum(@RequestParam("phone") String phone){
+        return ImmutableMap.of("times", voteInfoService.votedTimes(phone));
+    }
+}

+ 71 - 0
src/main/java/com/smcic/api/operate/entity/EnrollInfo.java

@@ -0,0 +1,71 @@
+package com.smcic.api.operate.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-10
+ */
+@Getter
+@Setter
+@TableName("operate_enroll_info")
+public class EnrollInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    private Integer operateId;
+
+    private String phone;
+
+    private String name;
+
+    private String university;
+
+    private String file;
+
+    private String type;
+
+    private String isOnLine;
+
+    private LocalDateTime updateTime;
+
+    private String introduction;
+
+    private Integer votes;
+
+    private Integer status;
+
+    private Integer sort;
+
+    private String workTitle;
+
+    public EnrollInfo() {
+    }
+
+    public EnrollInfo(String phone, String name, String university, String file, String isOnLine, String type, Integer operateId, String introduction, LocalDateTime updateTime, String workTitle) {
+        this.phone = phone;
+        this.name = name;
+        this.university = university;
+        this.file = file;
+        this.isOnLine = isOnLine;
+        this.updateTime = updateTime;
+        this.type = type;
+        this.operateId =  operateId;
+        this.introduction = introduction;
+        this.workTitle = workTitle;
+    }
+}

+ 41 - 0
src/main/java/com/smcic/api/operate/entity/Operate.java

@@ -0,0 +1,41 @@
+package com.smcic.api.operate.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-10
+ */
+@Getter
+@Setter
+@TableName("operate")
+public class Operate implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "operate_id", type = IdType.AUTO)
+    private Integer operateId;
+
+    private String operateName;
+
+    private String operateDesc;
+
+    private LocalDateTime startTime;
+
+    private LocalDateTime endTime;
+
+    private Integer status;
+
+
+}

+ 50 - 0
src/main/java/com/smcic/api/operate/entity/Users.java

@@ -0,0 +1,50 @@
+package com.smcic.api.operate.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-08
+ */
+@Getter
+@Setter
+@TableName("operate_users")
+public class Users implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Integer userId;
+
+    private String userName;
+
+    private String phone;
+
+    private String addr;
+
+    // 最大抽奖次数
+    private Integer maxDrawNum = 2;
+
+    // 已抽奖次数
+    private Integer drewNum;
+
+    private Integer operateId = 1;
+
+    // 剩余抽奖次数
+    private Integer drawNum;
+
+    @TableField(exist = false)
+    private String verifyCode;
+
+}

+ 33 - 0
src/main/java/com/smcic/api/operate/entity/VerifyCode.java

@@ -0,0 +1,33 @@
+package com.smcic.api.operate.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-09
+ */
+@Getter
+@Setter
+@TableName("operate_verify_code")
+public class VerifyCode implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId
+    private String phone;
+
+    private String code;
+
+    private Long expireTime;
+
+
+}

+ 51 - 0
src/main/java/com/smcic/api/operate/entity/VoteInfo.java

@@ -0,0 +1,51 @@
+package com.smcic.api.operate.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-16
+ */
+@Getter
+@Setter
+@TableName("operate_vote_info")
+public class VoteInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    private String target;
+
+    private String source;
+
+    private String client;
+
+    private LocalDateTime createTime;
+
+    private LocalDate dt;
+
+    public VoteInfo() {
+    }
+
+    public VoteInfo(String target, String source, String client, LocalDateTime createTime, LocalDate dt) {
+        this.target = target;
+        this.source = source;
+        this.client = client;
+        this.createTime = createTime;
+        this.dt = dt;
+    }
+}

+ 80 - 0
src/main/java/com/smcic/api/operate/job/Kafka2Db.java

@@ -0,0 +1,80 @@
+package com.smcic.api.operate.job;
+
+import cn.hutool.core.lang.generator.SnowflakeGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.smcic.api.operate.entity.VoteInfo;
+import com.smcic.api.operate.service.impl.VoteInfoServiceImpl;
+import lombok.extern.log4j.Log4j;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.consumer.KafkaConsumer;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Component
+@Slf4j
+public class Kafka2Db {
+
+    @Resource
+    private KafkaConsumer<String, String> consumer;
+
+    @Resource
+    private ThreadPoolExecutor threadPoolExecutor;
+
+    @PostConstruct
+    public void init(){
+        threadPoolExecutor.execute(this::run);
+    }
+
+    @Resource
+    private VoteInfoServiceImpl voteInfoService;
+
+    @Resource
+    private ObjectMapper objectMapper;
+
+    @Resource
+    private RedisTemplate<String, String> redisTemplate;
+
+    private final SnowflakeGenerator snowflakeGenerator = new SnowflakeGenerator(1, 1);
+
+    public void run() {
+        consumer.subscribe(Collections.singleton("operate_vote_queue"));
+        String lockKey = "OPERATE_KAFKA_LOCK";
+        long id = snowflakeGenerator.next();
+        while (true) {
+            Boolean success = redisTemplate.opsForValue().setIfAbsent(lockKey, String.valueOf(id), Duration.ofSeconds(3));
+            if (Boolean.FALSE.equals(success)){
+                break;
+            }
+            List<VoteInfo> voteInfos = new ArrayList<>();
+            consumer.poll(Duration.ofMillis(300)).forEach((record) -> {
+                log.info("读取数据 topic:{}, offset: {}, data: {}, 时间: {}", record.topic(),record.offset(),record.value(), record.timestamp());
+                VoteInfo voteInfo;
+                try {
+                    voteInfo = objectMapper.readValue(record.value(), VoteInfo.class);
+                    voteInfos.add(voteInfo);
+                } catch (JsonProcessingException e) {
+                    log.error("反序列化失败", e);
+                }
+            });
+            if(!voteInfos.isEmpty()){
+                try {
+                    voteInfoService.saveBatch(voteInfos);
+                    consumer.commitSync();
+                }catch (Exception e){
+                    log.error("提交失败", e);
+                }
+            }
+            redisTemplate.delete(lockKey);
+        }
+
+    }
+}

+ 18 - 0
src/main/java/com/smcic/api/operate/mapper/EnrollInfoMapper.java

@@ -0,0 +1,18 @@
+package com.smcic.api.operate.mapper;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.smcic.api.operate.entity.EnrollInfo;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-10
+ */
+
+public interface EnrollInfoMapper extends BaseMapper<EnrollInfo> {
+
+}

+ 18 - 0
src/main/java/com/smcic/api/operate/mapper/OperateMapper.java

@@ -0,0 +1,18 @@
+package com.smcic.api.operate.mapper;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.smcic.api.operate.entity.Operate;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-10
+ */
+
+public interface OperateMapper extends BaseMapper<Operate> {
+
+}

+ 18 - 0
src/main/java/com/smcic/api/operate/mapper/UsersMapper.java

@@ -0,0 +1,18 @@
+package com.smcic.api.operate.mapper;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.smcic.api.operate.entity.Users;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-08
+ */
+
+public interface UsersMapper extends BaseMapper<Users> {
+
+}

+ 18 - 0
src/main/java/com/smcic/api/operate/mapper/VerifyCodeMapper.java

@@ -0,0 +1,18 @@
+package com.smcic.api.operate.mapper;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.smcic.api.operate.entity.VerifyCode;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-09
+ */
+
+public interface VerifyCodeMapper extends BaseMapper<VerifyCode> {
+
+}

+ 18 - 0
src/main/java/com/smcic/api/operate/mapper/VoteInfoMapper.java

@@ -0,0 +1,18 @@
+package com.smcic.api.operate.mapper;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.smcic.api.operate.entity.VoteInfo;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-16
+ */
+
+public interface VoteInfoMapper extends BaseMapper<VoteInfo> {
+
+}

+ 16 - 0
src/main/java/com/smcic/api/operate/service/IEnrollInfoService.java

@@ -0,0 +1,16 @@
+package com.smcic.api.operate.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.smcic.api.operate.entity.EnrollInfo;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-10
+ */
+public interface IEnrollInfoService extends IService<EnrollInfo> {
+
+}

+ 16 - 0
src/main/java/com/smcic/api/operate/service/IOperateService.java

@@ -0,0 +1,16 @@
+package com.smcic.api.operate.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.smcic.api.operate.entity.Operate;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-10
+ */
+public interface IOperateService extends IService<Operate> {
+
+}

+ 16 - 0
src/main/java/com/smcic/api/operate/service/IUsersService.java

@@ -0,0 +1,16 @@
+package com.smcic.api.operate.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.smcic.api.operate.entity.Users;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-08
+ */
+public interface IUsersService extends IService<Users> {
+
+}

+ 16 - 0
src/main/java/com/smcic/api/operate/service/IVerifyCodeService.java

@@ -0,0 +1,16 @@
+package com.smcic.api.operate.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.smcic.api.operate.entity.VerifyCode;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-09
+ */
+public interface IVerifyCodeService extends IService<VerifyCode> {
+
+}

+ 16 - 0
src/main/java/com/smcic/api/operate/service/IVoteInfoService.java

@@ -0,0 +1,16 @@
+package com.smcic.api.operate.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.smcic.api.operate.entity.VoteInfo;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-16
+ */
+public interface IVoteInfoService extends IService<VoteInfo> {
+
+}

+ 42 - 0
src/main/java/com/smcic/api/operate/service/OSSService.java

@@ -0,0 +1,42 @@
+package com.smcic.api.operate.service;
+
+import cn.hutool.core.io.IoUtil;
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.SneakyThrows;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+@Service
+public class OSSService {
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    private final OSS ossClient = new OSSClientBuilder().build("https://oss-cn-chengdu.aliyuncs.com",
+            "LTAI4GEBqfF1GX4VwsYU2Wpg",
+            "rVIv0E1lRfXOCrAmkFTZnfgWiuv4ea");
+
+    @SneakyThrows
+    public void put(String bucketName, String key, String data) {
+        ossClient.putObject(bucketName, key, new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)));
+    }
+
+    @SneakyThrows
+    public void put(String bucketName, String key, MultipartFile file) {
+        ossClient.putObject(bucketName, key, new ByteArrayInputStream(IoUtil.readBytes(file.getInputStream())));
+    }
+
+    @SneakyThrows
+    public JsonNode getSortJson() {
+        InputStream objectContent = ossClient.getObject("dangjian-web", "miniProgrammeData/sort.json").getObjectContent();
+        String json = IoUtil.readUtf8(objectContent);
+        return objectMapper.readTree(json);
+    }
+}

+ 74 - 0
src/main/java/com/smcic/api/operate/service/impl/EnrollInfoServiceImpl.java

@@ -0,0 +1,74 @@
+package com.smcic.api.operate.service.impl;
+
+import cn.hutool.core.date.DateTime;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.smcic.api.operate.entity.EnrollInfo;
+import com.smcic.api.operate.mapper.EnrollInfoMapper;
+import com.smcic.api.operate.service.IEnrollInfoService;
+import com.smcic.api.operate.service.OSSService;
+import org.apache.http.util.TextUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-10
+ */
+@Service
+public class EnrollInfoServiceImpl extends ServiceImpl<EnrollInfoMapper, EnrollInfo> implements IEnrollInfoService {
+    @Resource
+    private OSSService ossService;
+
+    @Resource
+    private VoteInfoServiceImpl voteInfoService;
+
+    public void store(String phone, String name, String university, String isOnLine, String type, Integer operateId, String introduction, String workTitle, MultipartFile file){
+
+        String url = null;
+        if(null != file){
+            String path = "enroll/" + phone + "/" + (new DateTime().toString("yyyyMMddHHmmss")) + "/" + file.getOriginalFilename();
+            ossService.put("smcic-index", path, file);
+
+            url = "https://cxzx.smcic.net/" + path;
+        }
+        EnrollInfo enrollInfo = new EnrollInfo(phone, name, university, url, isOnLine, type, operateId, introduction, LocalDateTime.now(), workTitle);
+        EnrollInfo one = lambdaQuery().eq(EnrollInfo::getPhone, phone).one();
+
+        if (null != one){
+//            BeanUtils.copyProperties(enrollInfo, one);
+            one.setFile(enrollInfo.getFile());
+            one.setName(enrollInfo.getName());
+            one.setIntroduction(enrollInfo.getIntroduction());
+            one.setUpdateTime(enrollInfo.getUpdateTime());
+            one.setType(enrollInfo.getType());
+            updateById(one);
+        }else{
+            save(enrollInfo);
+        }
+    }
+
+    public List<EnrollInfo> list(String type, Integer operate, String phone){
+        voteInfoService.lsVerify(phone);
+
+        return lambdaQuery().eq(!TextUtils.isEmpty(type), EnrollInfo::getType, type).eq(EnrollInfo::getOperateId, operate)
+                .eq(EnrollInfo::getStatus, 1)
+                .orderByAsc(EnrollInfo::getSort).list();
+    }
+
+    public List<EnrollInfo> rank(String type, Integer operate, String phone){
+        voteInfoService.lsVerify(phone);
+
+        return lambdaQuery().eq(!TextUtils.isEmpty(type), EnrollInfo::getType, type).eq(EnrollInfo::getOperateId, operate)
+                .eq(EnrollInfo::getStatus, 1)
+                .orderByDesc(EnrollInfo::getVotes).list();
+    }
+
+}

+ 36 - 0
src/main/java/com/smcic/api/operate/service/impl/OperateServiceImpl.java

@@ -0,0 +1,36 @@
+package com.smcic.api.operate.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.smcic.api.operate.entity.Operate;
+import com.smcic.api.operate.mapper.OperateMapper;
+import com.smcic.api.operate.service.IOperateService;
+import com.smcic.core.advice.APIException;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-10
+ */
+@Service
+public class OperateServiceImpl extends ServiceImpl<OperateMapper, Operate> implements IOperateService {
+
+    public void verify(Integer operateId){
+        LocalDateTime now = LocalDateTime.now();
+        Operate ope = getById(operateId);
+
+        if(null != ope.getStartTime() && ope.getStartTime().isAfter(now)){
+            throw new APIException(400, "活动尚未开始");
+        }
+
+        if(null != ope.getEndTime() && ope.getEndTime().isBefore(now)){
+            throw new APIException(400, "活动已经结束");
+        }
+
+    }
+}

+ 179 - 0
src/main/java/com/smcic/api/operate/service/impl/UsersServiceImpl.java

@@ -0,0 +1,179 @@
+package com.smcic.api.operate.service.impl;
+
+import cn.hutool.core.util.RandomUtil;
+import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
+import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
+import com.aliyun.teaopenapi.models.Config;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.smcic.api.operate.entity.Users;
+import com.smcic.api.operate.entity.VerifyCode;
+import com.smcic.api.operate.mapper.UsersMapper;
+import com.smcic.api.operate.mapper.VerifyCodeMapper;
+import com.smcic.api.operate.service.IUsersService;
+import com.smcic.core.advice.APIException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-08
+ */
+@Service
+public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements IUsersService {
+
+    @Resource
+    private VerifyCodeMapper verifyCodeMapper;
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @Resource
+    private OperateServiceImpl operateService;
+
+    private final Logger log = LoggerFactory.getLogger(this.getClass());
+
+    private com.aliyun.dysmsapi20170525.Client client;
+
+    {
+        try {
+            client = new com.aliyun.dysmsapi20170525.Client(new Config()
+                    .setAccessKeyId("LTAI4GEBqfF1GX4VwsYU2Wpg")
+                    .setAccessKeySecret("rVIv0E1lRfXOCrAmkFTZnfgWiuv4ea")
+                    .setEndpoint("dysmsapi.aliyuncs.com"));
+        } catch (Exception e) {
+            log.error(e.getMessage(),e);
+            System.exit(1);
+        }
+    }
+
+    public void verifyCode(String phone, String code) {
+        VerifyCode verifyCode = verifyCodeMapper.selectOne(new LambdaQueryWrapper<VerifyCode>()
+                .eq(VerifyCode::getPhone, phone)
+                .eq(VerifyCode::getCode, code)
+        );
+        if (verifyCode == null) {
+            throw new APIException(400, "验证码错误");
+        }
+        if (System.currentTimeMillis() > verifyCode.getExpireTime()) {
+            throw new APIException(400, "验证码已超时,请重新发送");
+        }
+    }
+
+    public void sendVerifyCode(String phone) {
+        String pattern = "^1\\d{10}$";
+        Pattern p = Pattern.compile(pattern);
+        Matcher match =  p.matcher(phone);
+        if(!match.matches()){
+            throw new APIException(400, "请输入正确的手机号码");
+        }
+
+        VerifyCode verifyCode = verifyCodeMapper.selectOne(new LambdaQueryWrapper<VerifyCode>()
+                .eq(VerifyCode::getPhone, phone)
+        );
+        if (verifyCode != null) {
+            if (System.currentTimeMillis() - (verifyCode.getExpireTime() - 60 * 5 * 1000) < 60 * 1000) {
+                throw new APIException("验证码已发送,请等待60秒后重新发送");
+            }
+            verifyCodeMapper.deleteById(phone);
+        }
+
+        String code = RandomUtil.randomNumbers(4);
+
+        if(phone.equals("18439106376")){
+            code = "0000";
+        }else{
+            SendSmsRequest sendSmsRequest = new SendSmsRequest()
+                    .setPhoneNumbers(phone)
+                    .setSignName("陕西广电融媒体集团")
+                    .setTemplateCode("SMS_213330092")
+                    .setTemplateParam("{\"code\":\""+code+"\"}");
+            // 复制代码运行请自行打印 API 的返回值
+            try {
+                SendSmsResponse sendSmsResponse = client.sendSms(sendSmsRequest);
+                log.info("sendSmsResponse {}",  objectMapper.writeValueAsString(sendSmsResponse.getBody()));
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+                throw new APIException("发送短信异常");
+            }
+        }
+
+        verifyCode = new VerifyCode();
+        verifyCode.setPhone(phone);
+        verifyCode.setCode(code);
+        // 5分钟的过期时间
+        verifyCode.setExpireTime(System.currentTimeMillis() + 60 * 5 * 1000);
+        verifyCodeMapper.insert(verifyCode);
+
+    }
+
+    public void store(Users user){
+        operateService.verify(user.getOperateId());
+        verifyCode(user.getPhone(), user.getVerifyCode());
+        Users one = lambdaQuery().eq(Users::getPhone, user.getPhone()).eq(Users::getOperateId, user.getOperateId()).one();
+        if(null != one){
+            one.setAddr(user.getAddr());
+            one.setUserName(user.getUserName());
+            updateById(one);
+        }else{
+            user.setMaxDrawNum(2);
+            user.setDrawNum(1);
+            save(user);
+        }
+
+    }
+
+    public void update(Users user){
+        operateService.verify(user.getOperateId());
+        Users one = lambdaQuery().eq(Users::getPhone, user.getPhone()).eq(Users::getOperateId, user.getOperateId()).one();
+        if(null == one){
+            throw new APIException(400, "不存在的用户");
+        }
+        one.setAddr(user.getAddr());
+        one.setUserName(user.getUserName());
+        updateById(one);
+
+    }
+
+    public Users getUserByPhone(String phone, Integer operateId){
+        Users one = lambdaQuery().eq(Users::getPhone, phone).eq(Users::getOperateId, operateId).one();
+        if (null == one){
+            throw new APIException(400, "不存在的用户");
+        }
+
+        //userDrawNumService.drawNumHandle(one);
+        return one;
+    }
+
+    public void drawPlus(String phone, Integer operateId){
+        Users one = lambdaQuery().eq(Users::getPhone, phone).eq(Users::getOperateId, operateId).one();
+        if (null == one){
+            throw new APIException(400, "不存在的用户");
+        }
+        //userDrawNumService.drawPlus(one);
+
+        if(one.getDrawNum() + one.getDrewNum() >= one.getMaxDrawNum()){
+            throw new APIException(400, "您的抽奖次数已达上限");
+        }
+
+        one.setDrawNum(one.getDrawNum() + 1);
+        updateById(one);
+    }
+
+    public void drawDec(Users users){
+        users.setDrawNum(users.getDrawNum() - 1);
+        users.setDrewNum(users.getDrewNum() + 1);
+        updateById(users);
+    }
+}

+ 20 - 0
src/main/java/com/smcic/api/operate/service/impl/VerifyCodeServiceImpl.java

@@ -0,0 +1,20 @@
+package com.smcic.api.operate.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.smcic.api.operate.entity.VerifyCode;
+import com.smcic.api.operate.mapper.VerifyCodeMapper;
+import com.smcic.api.operate.service.IVerifyCodeService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-09
+ */
+@Service
+public class VerifyCodeServiceImpl extends ServiceImpl<VerifyCodeMapper, VerifyCode> implements IVerifyCodeService {
+
+}

+ 151 - 0
src/main/java/com/smcic/api/operate/service/impl/VoteInfoServiceImpl.java

@@ -0,0 +1,151 @@
+package com.smcic.api.operate.service.impl;
+
+import cn.hutool.core.lang.Snowflake;
+import cn.hutool.core.lang.generator.SnowflakeGenerator;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.smcic.api.operate.entity.EnrollInfo;
+import com.smcic.api.operate.entity.VoteInfo;
+import com.smcic.api.operate.mapper.VoteInfoMapper;
+import com.smcic.api.operate.service.IVoteInfoService;
+import com.smcic.core.advice.APIException;
+import org.apache.http.util.TextUtils;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Map;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author syj
+ * @since 2022-12-16
+ */
+@Service
+public class VoteInfoServiceImpl extends ServiceImpl<VoteInfoMapper, VoteInfo> implements IVoteInfoService {
+
+    @Resource
+    private EnrollInfoServiceImpl enrollInfoService;
+
+    @Resource
+    private OperateServiceImpl operateService;
+
+    @Resource
+    private RedisTemplate<String, String> redisTemplate;
+
+    private final SnowflakeGenerator snowflakeGenerator = new SnowflakeGenerator(1, 1);
+
+    @Resource
+    private KafkaTemplate kafkaTemplate;
+
+    @Resource
+    private ObjectMapper objectMapper;
+
+    public void vote(String target, String source, String client, Integer operateId){
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
+        String dt = formatter.format(LocalDate.now());
+        operateService.verify(operateId);
+        long max = 2L;
+        if(client.equals("闪视频")){
+            max = 10L;
+        }
+
+        /*EnrollInfo one = enrollInfoService.lambdaQuery().eq(EnrollInfo::getPhone, target).eq(EnrollInfo::getOperateId, operateId).one();
+
+        if(null == one){
+            throw new APIException(400, "不存在的目标");
+        }*/
+        String one = redisTemplate.opsForValue().get("OPERATE_TARGET_" + operateId + "_" + target);
+
+        if (null == one){
+            throw new APIException(400, "不存在的目标");
+        }
+
+        String vds = redisTemplate.opsForValue().get("OPERATE_DT_SOURCE_" + operateId + "_"+ dt + "_" + source);
+        long vd;
+        if(TextUtils.isEmpty(vds)){
+            vd = 0L;
+        }else{
+            vd = Long.parseLong(vds);
+        }
+
+        // Long vd = lambdaQuery().eq(VoteInfo::getSource, source).gt(VoteInfo::getCreateTime, LocalDate.now()).count();
+
+        if (vd >= max){
+            if(client.equals("闪视频")){
+                throw new APIException(400, "今日投票次数已用完,请明日再来!");
+            }else{
+                throw new APIException(400, "今日投票次数已用完,点击下载闪视频获取更多投票机会!");
+            }
+        }
+
+        long id = snowflakeGenerator.next();
+
+        String lockKey = "OPERATE_SOURCE_LOCK_" + operateId + "_" + source;
+        while (true){
+            Boolean success = redisTemplate.opsForValue().setIfAbsent(lockKey, String.valueOf(id), Duration.ofSeconds(3));
+
+            if (Boolean.TRUE.equals(success)){
+                vds = redisTemplate.opsForValue().get("OPERATE_DT_SOURCE_" + operateId + "_"+ dt + "_" + source);
+                if(TextUtils.isEmpty(vds)){
+                    vd = 0L;
+                }else{
+                    vd = Long.parseLong(vds);
+                }
+                if (vd >= max){
+                    redisTemplate.delete(lockKey);
+                    if(client.equals("闪视频")){
+                        throw new APIException(400, "今日投票次数已用完,请明日再来!");
+                    }else{
+                        throw new APIException(400, "今日投票次数已用完,点击下载闪视频获取更多投票机会!");
+                    }
+                }
+
+
+                try {
+                    kafkaTemplate.send("operate_vote_queue",
+                            objectMapper.writeValueAsString(
+                                    new VoteInfo(target, source, client, LocalDateTime.now(), LocalDate.now())
+                    ));
+                } catch (JsonProcessingException e) {
+                    throw new RuntimeException(e);
+                }
+                redisTemplate.opsForValue().increment("OPERATE_DT_SOURCE_" + operateId + "_"+ dt + "_" + source);
+                redisTemplate.expire("OPERATE_DT_SOURCE_" + operateId + "_"+ dt + "_" + source, Duration.ofDays(1));
+                redisTemplate.delete(lockKey);
+                break;
+            }
+        }
+
+
+
+        /*one.setVotes(one.getVotes()+1);
+        enrollInfoService.updateById(one);
+
+        VoteInfo voteInfo = new VoteInfo(target, source, client, LocalDateTime.now(), LocalDate.now());
+        save(voteInfo);*/
+
+    }
+
+    public void lsVerify(String phone){
+        if(!TextUtils.isEmpty(phone) && votedTimes(phone) < 5){
+            throw new APIException("您暂无查看权限");
+        }
+    }
+
+    public Long votedTimes(String phone){
+        return lambdaQuery().eq(VoteInfo::getSource, phone).eq(VoteInfo::getDt, LocalDate.now()).count();
+    }
+
+}

+ 125 - 0
src/main/java/com/smcic/core/conf/KafkaConfig.java

@@ -0,0 +1,125 @@
+package com.smcic.core.conf;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.kafka.clients.CommonClientConfigs;
+import org.apache.kafka.clients.consumer.ConsumerConfig;
+import org.apache.kafka.clients.consumer.KafkaConsumer;
+import org.apache.kafka.clients.producer.KafkaProducer;
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.apache.kafka.common.config.SaslConfigs;
+import org.apache.kafka.common.config.SslConfigs;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.core.DefaultKafkaProducerFactory;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.core.ProducerFactory;
+
+
+import java.io.File;
+import java.util.Map;
+import java.util.Properties;
+
+@Configuration
+public class KafkaConfig {
+
+
+    @Value("${spring.kafka.bootstrap-servers}")
+    private String bootstrapServers;
+
+    @Bean
+    public KafkaProducer kafkaProducer() {
+        File userDir = SystemUtils.getUserDir();
+        String jksPath = FilenameUtils.concat(userDir.getAbsolutePath(), "conf/only.4096.client.truststore.jks");
+        String jaasPath = FilenameUtils.concat(userDir.getAbsolutePath(), "conf/kafka_client_jaas.conf");
+
+        Properties props = new Properties();
+        //根证书store的密码,保持不变。
+        //接入协议,目前支持使用SASL_SSL协议接入。
+        props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
+        //SASL鉴权方式,保持不变。
+        props.put(SaslConfigs.SASL_MECHANISM, "PLAIN");
+        props.put(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, jksPath);
+        //根证书store的密码,保持不变。
+        props.put(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, "KafkaOnsClient");
+        props.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, "");
+        System.setProperty("java.security.auth.login.config", jaasPath);
+        props.put("bootstrap.servers",
+                bootstrapServers);
+
+        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+        //创建Kafka生产者
+        return new KafkaProducer(props);
+    }
+
+    @Bean
+    public KafkaConsumer kafkaConsumer(){
+        File userDir = SystemUtils.getUserDir();
+        String jksPath = FilenameUtils.concat(userDir.getAbsolutePath(), "conf/only.4096.client.truststore.jks");
+        String jaasPath = FilenameUtils.concat(userDir.getAbsolutePath(), "conf/kafka_client_jaas.conf");
+        Properties props = new Properties();
+        //根证书store的密码,保持不变。
+        //接入协议,目前支持使用SASL_SSL协议接入。
+        props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
+        props.put(CommonClientConfigs.GROUP_ID_CONFIG, "cxzx");
+        //SASL鉴权方式,保持不变。
+        props.put(SaslConfigs.SASL_MECHANISM, "PLAIN");
+        props.put(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, jksPath);
+        //根证书store的密码,保持不变。
+        props.put(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, "KafkaOnsClient");
+        props.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, "");
+        System.setProperty("java.security.auth.login.config", jaasPath);
+        props.put("bootstrap.servers", bootstrapServers);
+        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
+        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
+        props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
+        props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
+
+        //注意该值不要改得太大,如果Poll太多数据,而不能在下次Poll之前消费完,则会触发一次负载均衡,产生卡顿。
+        props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 500);
+        props.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, 300 * 1000);
+        //创建Kafka消费者
+        return new KafkaConsumer(props);
+    }
+
+    // 根据生产者工厂构建kafkaTemplate
+    @Bean
+    public KafkaTemplate<String, String> kafkaTemplate(ProducerFactory<String, String> producerFactory) {
+        KafkaTemplate<String, String> kafkaTemplate = new KafkaTemplate<>(producerFactory);
+        return kafkaTemplate;
+    }
+
+    // 将一个生产者工厂注册到spring容器中
+    @Bean
+    public ProducerFactory<String, String> producerFactory() {
+
+        KafkaProperties kafkaProperties = new KafkaProperties();
+        Map<String, Object> props = kafkaProperties.buildProducerProperties();
+        File userDir = SystemUtils.getUserDir();
+        String jksPath = FilenameUtils.concat(userDir.getAbsolutePath(), "conf/only.4096.client.truststore.jks");
+        String jaasPath = FilenameUtils.concat(userDir.getAbsolutePath(), "conf/kafka_client_jaas.conf");
+
+        //根证书store的密码,保持不变。
+        //接入协议,目前支持使用SASL_SSL协议接入。
+        //根证书store的密码,保持不变。
+        //接入协议,目前支持使用SASL_SSL协议接入。
+        props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
+        //SASL鉴权方式,保持不变。
+        props.put(SaslConfigs.SASL_MECHANISM, "PLAIN");
+        props.put(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, jksPath);
+        //根证书store的密码,保持不变。
+        props.put(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, "KafkaOnsClient");
+        props.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, "");
+        System.setProperty("java.security.auth.login.config", jaasPath);
+        props.put("bootstrap.servers",
+                bootstrapServers);
+
+        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+        return new DefaultKafkaProducerFactory<>(props);
+    }
+}

+ 126 - 0
src/main/java/com/smcic/core/conf/RedisConfig.java

@@ -0,0 +1,126 @@
+package com.smcic.core.conf;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.*;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * @author janti
+ * reids 相关bean的配置
+ */
+@Configuration
+@EnableCaching
+public class RedisConfig extends CachingConfigurerSupport {
+
+    /**
+     * 选择redis作为默认缓存工具
+     * @param redisTemplate
+     * @return
+     */
+    /*@Bean
+    public CacheManager cacheManager(RedisTemplate redisTemplate) {
+        RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
+        return rcm;
+    }*/
+
+    /**
+     * retemplate相关配置
+     * @param factory
+     * @return
+     */
+    @Bean
+    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
+
+        RedisTemplate<String, Object> template = new RedisTemplate<>();
+        // 配置连接工厂
+        template.setConnectionFactory(factory);
+
+        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
+        Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
+
+        ObjectMapper om = new ObjectMapper();
+        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
+        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
+        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+        jacksonSeial.setObjectMapper(om);
+
+        // 值采用json序列化
+        /*template.setValueSerializer(jacksonSeial);*/
+        //使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+        template.setValueSerializer(new StringRedisSerializer());
+
+        // 设置hash key 和value序列化模式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(jacksonSeial);
+        template.afterPropertiesSet();
+
+        return template;
+    }
+
+    /**
+     * 对hash类型的数据操作
+     *
+     * @param redisTemplate
+     * @return
+     */
+    @Bean
+    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
+        return redisTemplate.opsForHash();
+    }
+
+    /**
+     * 对redis字符串类型数据操作
+     *
+     * @param redisTemplate
+     * @return
+     */
+    @Bean
+    public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
+        return redisTemplate.opsForValue();
+    }
+
+    /**
+     * 对链表类型的数据操作
+     *
+     * @param redisTemplate
+     * @return
+     */
+    @Bean
+    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
+        return redisTemplate.opsForList();
+    }
+
+    /**
+     * 对无序集合类型的数据操作
+     *
+     * @param redisTemplate
+     * @return
+     */
+    @Bean
+    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
+        return redisTemplate.opsForSet();
+    }
+
+    /**
+     * 对有序集合类型的数据操作
+     *
+     * @param redisTemplate
+     * @return
+     */
+    @Bean
+    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
+        return redisTemplate.opsForZSet();
+    }
+}

+ 8 - 0
src/main/resources/application.yml

@@ -44,6 +44,14 @@ spring:
           username: cxzx
           password: sxtvs53$68HD
 
+  redis:
+    host: r-2vch6mmrbgv8vjc44epd.redis.cn-chengdu.rds.aliyuncs.com
+    port: 6379
+    password: vkckussJJCBX&^55sd
+    database: 0
+  kafka:
+    bootstrap-servers: alikafka-pre-cn-tl32wxejg003-1.alikafka.aliyuncs.com:9093,alikafka-pre-cn-tl32wxejg003-2.alikafka.aliyuncs.com:9093,alikafka-pre-cn-tl32wxejg003-3.alikafka.aliyuncs.com:9093
+
   jackson:
     time-zone: GMT+8
     date-format: "yyyy-MM-dd HH:mm:ss"