This commit is contained in:
chenglijuan
2026-04-21 11:30:56 +08:00
commit 14e6058725
23 changed files with 721 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
# Maven
target/
*.class
*.jar
*.war
*.ear
# IDE
.idea/
*.iml
.vscode/
*.iml
# Logs
*.log
+10
View File
@@ -0,0 +1,10 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# 已忽略包含查询文件的默认文件夹
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="ms-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/mini_program.iml" filepath="$PROJECT_DIR$/mini_program.iml" />
</modules>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+63
View File
@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>mini_program</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>mini_program</name>
<description>Spring Boot Demo Project</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- Spring Boot Web Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
+1
View File
@@ -0,0 +1 @@
ssh -R 1616:localhost:8080 root@xcx.yun.588580.xyz
@@ -0,0 +1,11 @@
package com.example.mini_program;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MiniProgramApplication {
public static void main(String[] args) {
SpringApplication.run(MiniProgramApplication.class, args);
}
}
@@ -0,0 +1,13 @@
package main.java.com.example.mini_program.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, Spring Boot!";
}
}
@@ -0,0 +1,15 @@
package main.java.com.example.mini_program.controller.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class Demo3Application {
public static void main(String[] args) {
SpringApplication.run(Demo3Application.class, args);
}
}
@@ -0,0 +1,36 @@
package main.java.com.example.mini_program.controller.demo.mini;
import com.example.demo.mini.entity.VisitApplication;
import com.example.demo.mini.mapper.VisitApplicationMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service
public class AppointmentService {
private static final Logger logger = LoggerFactory.getLogger(AppointmentService.class);
private final VisitApplicationMapper visitApplicationMapper;
public AppointmentService(VisitApplicationMapper visitApplicationMapper) {
this.visitApplicationMapper = visitApplicationMapper;
}
/**
* 根据openid获取最新的一条预约记录
*
* @param openid 微信用户openid
* @return 最新的一条预约记录,没有则返回null
*/
public VisitApplication getLatest(String openid) {
logger.info("查询用户最新预约记录, openid: {}", openid);
VisitApplication result = visitApplicationMapper.selectLatestByOpenid(openid);
if (result != null) {
logger.info("找到预约记录, id: {}", result.getId());
} else {
logger.info("未找到预约记录");
}
return result;
}
}
@@ -0,0 +1,109 @@
package main.java.com.example.mini_program.controller.demo.mini;
import com.example.demo.mini.entity.VisitApplication;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/wx-mini")
public class WxLoginController {
private final WxLoginService wxLoginService;
private final AppointmentService appointmentService;
public WxLoginController(WxLoginService wxLoginService, AppointmentService appointmentService) {
this.wxLoginService = wxLoginService;
this.appointmentService = appointmentService;
}
/**
* 微信小程序登录接口
* 接收wx.login的code,换取openid
*
* @param code 小程序wx.login获取的code
* @return openid等信息
*/
@GetMapping("/login")
public Result<WxLoginResult> login(@RequestParam String code) {
if (code == null || code.trim().isEmpty()) {
return Result.error("code不能为空");
}
WxLoginResult result = wxLoginService.code2Session(code);
if ("0".equals(result.getErrcode())|| "".equals(result.getErrcode())) {
return Result.success(result);
} else {
return Result.error(result.getErrcode(), result.getErrmsg());
}
}
/**
* 根据openid获取最新的一条预约记录
*
* @param openid 微信用户openid
* @return 最新的一条预约记录
*/
@GetMapping("/appointment/latest")
public Result<VisitApplication> getLatestAppointment(@RequestParam String openid) {
if (openid == null || openid.trim().isEmpty()) {
return Result.error("openid不能为空");
}
VisitApplication appointment = appointmentService.getLatest(openid);
return Result.success(appointment);
}
/**
* 统一返回结果类
*/
public static class Result<T> {
private int code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(0);
result.setMessage("success");
result.setData(data);
return result;
}
public static <T> Result<T> error(String message) {
Result<T> result = new Result<>();
result.setCode(-1);
result.setMessage(message);
return result;
}
public static <T> Result<T> error(String code, String message) {
Result<T> result = new Result<>();
result.setCode(-1);
result.setMessage(code + ": " + message);
return result;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
}
@@ -0,0 +1,50 @@
package main.java.com.example.mini_program.controller.demo.mini;
public class WxLoginResult {
private String session_key;
private String unionid;
private String openid;
private String errcode;
private String errmsg;
public String getSession_key() {
return session_key;
}
public void setSession_key(String session_key) {
this.session_key = session_key;
}
public String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getErrcode() {
return errcode;
}
public void setErrcode(String errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
}
@@ -0,0 +1,61 @@
package main.java.com.example.mini_program.controller.demo.mini;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class WxLoginService {
private static final Logger logger = LoggerFactory.getLogger(WxLoginService.class);
private static final String JSCODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
private final WxMiniAppConfig wxMiniAppConfig;
private final RestTemplate restTemplate;
public WxLoginService(WxMiniAppConfig wxMiniAppConfig) {
this.wxMiniAppConfig = wxMiniAppConfig;
this.restTemplate = new RestTemplate();
}
/**
* 调用微信接口用code换取openid
*
* @param code 小程序调用wx.login获取的code
* @return 登录结果,包含openid等信息
*/
public WxLoginResult code2Session(String code) {
String url = String.format(JSCODE2SESSION_URL,
wxMiniAppConfig.getAppid(),
wxMiniAppConfig.getSecret(),
code);
logger.info("调用微信jscode2session接口,code: {}", code);
try {
// 微信返回text/plain,手动解析JSON字符串
String response = restTemplate.getForObject(url, String.class);
logger.info("微信返回原始结果: {}", response);
JSONObject json = new JSONObject(response);
WxLoginResult result = new WxLoginResult();
result.setOpenid(json.optString("openid"));
result.setSession_key(json.optString("session_key"));
result.setUnionid(json.optString("unionid"));
result.setErrcode(json.optString("errcode"));
result.setErrmsg(json.optString("errmsg"));
logger.info("解析后结果: openid={}, unionid={}, errcode={}",
result.getOpenid(), result.getUnionid(), result.getErrcode());
return result;
} catch (Exception e) {
logger.error("调用微信接口失败", e);
WxLoginResult errorResult = new WxLoginResult();
errorResult.setErrcode("-1");
errorResult.setErrmsg("系统错误: " + e.getMessage());
return errorResult;
}
}
}
@@ -0,0 +1,28 @@
package main.java.com.example.mini_program.controller.demo.mini;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "wx.miniapp")
public class WxMiniAppConfig {
private String appid;
private String secret;
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
}
@@ -0,0 +1,54 @@
-- --------------------------------------------------------
-- 主机: txy.588580.xyz
-- 服务器版本: 5.7.44 - MySQL Community Server (GPL)
-- 服务器操作系统: Linux
-- HeidiSQL 版本: 12.17.0.7270
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-- 导出 mini 的数据库结构
CREATE DATABASE IF NOT EXISTS `mini` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `mini`;
-- 导出 表 mini.visit_application 结构
CREATE TABLE IF NOT EXISTS `visit_application` (
`id` varchar(32) NOT NULL COMMENT '主键ID',
`name` varchar(50) NOT NULL COMMENT '访客姓名',
`phone` varchar(20) NOT NULL COMMENT '联系电话',
`company` varchar(100) DEFAULT NULL COMMENT '公司名称',
`reason` varchar(500) DEFAULT NULL COMMENT '来访原因',
`visit_date` date NOT NULL COMMENT '来访日期',
`visit_time` time DEFAULT '00:00:00' COMMENT '来访时间',
`host_name` varchar(50) DEFAULT NULL COMMENT '接待人姓名',
`area` varchar(50) DEFAULT NULL COMMENT '访问区域',
`status` varchar(20) NOT NULL DEFAULT 'pending' COMMENT '状态',
`status_text` varchar(50) DEFAULT NULL COMMENT '状态文本描述',
`openid` varchar(64) DEFAULT NULL COMMENT '微信用户openid',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_status` (`status`),
KEY `idx_visit_date` (`visit_date`),
KEY `idx_openid` (`openid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问申请记录表';
-- 正在导出表 mini.visit_application 的数据:~4 rows (大约)
INSERT INTO `visit_application` (`id`, `name`, `phone`, `company`, `reason`, `visit_date`, `visit_time`, `host_name`, `area`, `status`, `status_text`, `openid`, `create_time`) VALUES
('16a235b169e3405200194dd91bc3e36f', '吴松', '12311111111', 'hj', 'jkk', '2026-04-18', '00:00:00', 'clj', 'B区-办公楼', 'cancelled', '已取消', 'ogzdF3d3Z494n28mxsUUHvASiePE', '2026-04-18 08:26:58'),
('5f19df4769e3444d001856492c09fb78', 'k', '12224446798', 'j', '你说的这个是同步svn上的所有文件,还是某一个文件夹下的文件q', '2026-04-18', '00:00:00', 'lj', 'A区-生产车间', 'pending', '待审核', 'ogzdF3d3Z494n28mxsUUHvASiePE', '2026-04-18 08:43:57'),
('6cd8d0ff69e5f0f9004d447951241305', '陈良', '15056476763', '安影', '测试', '2026-04-20', '10:00:00', '虞欢溢', 'A区-生产车间', 'pending', '待审核', 'ogzdF3a-l23Vfpq14b7QEp1VEukg', '2026-04-20 09:25:13'),
('8b925adc69e5d944004a593558e0a944', '程利娟', '19805853215', '哈哈科技有限公司', '参观', '2026-04-21', '13:00:00', '生产部长', 'A区-生产车间', 'pending', '待审核', 'ogzdF3Vv42nydiUnY6lEW0ufK4Q0', '2026-04-20 07:44:04');
/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;
@@ -0,0 +1,4 @@
{"_id":"16a235b169e3405200194dd91bc3e36f","name":"吴松","phone":"12311111111","company":"hj","reason":"jkk","time":"00:00","hostName":"clj","area":"B区-办公楼","statusText":"已取消","date":"2026-04-18","status":"cancelled","createTime":{"$date":"2026-04-18T08:26:58.102Z"},"_openid":"ogzdF3d3Z494n28mxsUUHvASiePE"}
{"_id":"5f19df4769e3444d001856492c09fb78","statusText":"待审核","createTime":{"$date":"2026-04-18T08:43:57.985Z"},"_openid":"ogzdF3d3Z494n28mxsUUHvASiePE","phone":"12224446798","company":"j","reason":"你说的这个是同步svn上的所有文件,还是某一个文件夹下的文件q","date":"2026-04-18","time":"00:00","hostName":"lj","status":"pending","name":"k","area":"A区-生产车间"}
{"_id":"8b925adc69e5d944004a593558e0a944","_openid":"ogzdF3Vv42nydiUnY6lEW0ufK4Q0","name":"程利娟","company":"哈哈科技有限公司","reason":"参观","date":"2026-04-21","hostName":"生产部长","area":"A区-生产车间","status":"pending","createTime":{"$date":"2026-04-20T07:44:04.124Z"},"phone":"19805853215","time":"13:00","statusText":"待审核"}
{"_id":"6cd8d0ff69e5f0f9004d447951241305","name":"陈良","phone":"15056476763","reason":"测试","hostName":"虞欢溢","statusText":"待审核","createTime":{"$date":"2026-04-20T09:25:13.364Z"},"_openid":"ogzdF3a-l23Vfpq14b7QEp1VEukg","company":"安影","date":"2026-04-20","time":"10:00","area":"A区-生产车间","status":"pending"}
@@ -0,0 +1,3 @@
{"_id":"775c8c1769e34030001852fa5df8d835","_openid":"ogzdF3d3Z494n28mxsUUHvASiePE","avatarUrl":"wxfile://tmp_087ba7d96bc1da49c25cf77a6c2b6a90f03fffddcc59aecf.png","nickName":"i","createTime":{"$date":"2026-04-18T08:26:24.337Z"},"lastLoginTime":{"$date":"2026-04-20T09:47:25.222Z"}}
{"_id":"5065eed869e341aa0019a9352a21b8e4","_openid":"ogzdF3Vv42nydiUnY6lEW0ufK4Q0","avatarUrl":"http://tmp/q2RwR6L5kT1v2b4bd91956654d901dfa7b6cd59aa006.jpeg","nickName":"23","createTime":{"$date":"2026-04-18T08:32:42.356Z"},"lastLoginTime":{"$date":"2026-04-20T07:42:43.764Z"}}
{"_id":"775c8c1769e5f0cd00499e73707f0bb9","_openid":"ogzdF3a-l23Vfpq14b7QEp1VEukg","createTime":{"$date":"2026-04-20T09:24:29.069Z"},"lastLoginTime":{"$date":"2026-04-20T09:24:29.069Z"}}
@@ -0,0 +1,122 @@
package main.java.com.example.mini_program.controller.demo.mini.entity;
public class VisitApplication {
private String id;
private String name;
private String phone;
private String company;
private String reason;
private String visitDate;
private String visitTime;
private String hostName;
private String area;
private String status;
private String statusText;
private String openid;
private String createTime;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public String getVisitDate() {
return visitDate;
}
public void setVisitDate(String visitDate) {
this.visitDate = visitDate;
}
public String getVisitTime() {
return visitTime;
}
public void setVisitTime(String visitTime) {
this.visitTime = visitTime;
}
public String getHostName() {
return hostName;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatusText() {
return statusText;
}
public void setStatusText(String statusText) {
this.statusText = statusText;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
}
@@ -0,0 +1,17 @@
package main.java.com.example.mini_program.controller.demo.mini.mapper;
import com.example.demo.mini.entity.VisitApplication;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface VisitApplicationMapper {
/**
* 根据openid查询最新的一条预约记录
*
* @param openid 微信用户openid
* @return 最新的一条记录,没有则返回null
*/
VisitApplication selectLatestByOpenid(@Param("openid") String openid);
}
+45
View File
@@ -0,0 +1,45 @@
server:
port: 8080
spring:
application:
name: mini_program
datasource:
url: jdbc:mysql://txy.588580.xyz:3306/mini?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: 123
driver-class-name: com.mysql.cj.jdbc.Driver
redis:
# Redis 服务器地址
host: localhost
# Redis 服务器端口
port: 6379
# Redis 数据库索引(默认 0
database: 0
# 连接超时时间(毫秒)
timeout: 5000
# 连接池配置
lettuce:
pool:
# 最大连接数
max-active: 8
# 最大空闲连接数
max-idle: 8
# 最小空闲连接数
min-idle: 0
# 连接耗尽时的最大等待时间(负值表示无限等待)
max-wait: -1ms
# 微信小程序配置
wx:
miniapp:
# 小程序AppID
appid: wx50fe0c5c28dd3060
# 小程序AppSecret
secret: e82fa407fad13a9df35503f2d176e5a4
# MyBatis配置
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.demo.mini.entity
configuration:
map-underscore-to-camel-case: true
@@ -0,0 +1,33 @@
<?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.example.demo.mini.mapper.VisitApplicationMapper">
<resultMap id="BaseResultMap" type="com.example.demo.mini.entity.VisitApplication">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="phone" property="phone"/>
<result column="company" property="company"/>
<result column="reason" property="reason"/>
<result column="visit_date" property="visitDate"/>
<result column="visit_time" property="visitTime"/>
<result column="host_name" property="hostName"/>
<result column="area" property="area"/>
<result column="status" property="status"/>
<result column="status_text" property="statusText"/>
<result column="openid" property="openid"/>
<result column="create_time" property="createTime"/>
</resultMap>
<select id="selectLatestByOpenid" resultMap="BaseResultMap">
SELECT id, name, phone, company, reason,
DATE_FORMAT(visit_date, '%Y-%m-%d') AS visit_date,
DATE_FORMAT(visit_time, '%H:%i') AS visit_time,
host_name, area, status, status_text, openid,
DATE_FORMAT(create_time, '%Y-%m-%dT%H:%i:%s.000+00:00') AS create_time
FROM visit_application
WHERE openid = #{openid}
ORDER BY create_time DESC
LIMIT 1
</select>
</mapper>