├── src └── main │ ├── resources │ ├── tmp.png │ ├── META-INF │ │ └── additional-spring-configuration-metadata.json │ ├── templates │ │ ├── error.html │ │ └── uploadForm.html │ └── application.yml.template │ └── java │ └── io │ └── github │ └── jiezhi │ └── wx │ └── miniapp │ ├── model │ ├── Result.java │ ├── AllData.java │ ├── Location.java │ ├── Photo.java │ ├── WxUser.java │ ├── Attendance.java │ ├── Comment.java │ ├── Bless.java │ └── MainInfo.java │ ├── repository │ ├── AttendanceRepository.java │ ├── LocationRepository.java │ ├── MainInfoRepository.java │ ├── AlbumRepository.java │ ├── CommentRepository.java │ └── BlessRepository.java │ ├── config │ ├── StorageProperties.java │ ├── WxMaProperties.java │ └── WxMaConfiguration.java │ ├── error │ ├── StorageException.java │ ├── ErrorController.java │ └── ErrorPageConfiguration.java │ ├── utils │ ├── TimeUtils.java │ └── JsonUtils.java │ ├── storage │ └── StorageService.java │ ├── WxMaDemoApplication.java │ ├── controller │ ├── FileController.java │ ├── WxMaUserController.java │ ├── WxMaMediaController.java │ ├── WxPortalController.java │ └── AppController.java │ └── service │ └── FileSystemStorageService.java ├── .gitignore ├── Dockerfile ├── .travis.yml ├── .editorconfig ├── README.md ├── init.sql └── pom.xml /src/main/resources/tmp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jiezhi/marriage-miniapp-server/HEAD/src/main/resources/tmp.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.settings/ 3 | *.project 4 | *.classpath 5 | application.yml 6 | /.idea/ 7 | *.iml 8 | data.json 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | ADD weixin-java-miniapp-demo-1.0.0-SNAPSHOT.jar app.jar 4 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | 5 | script: "mvn clean package -Dmaven.test.skip=true" 6 | 7 | branches: 8 | only: 9 | - master 10 | 11 | notifications: 12 | email: 13 | - jiezhi.g+github@gmail.com 14 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": [ 3 | { 4 | "name": "wx.mp.configs", 5 | "type": "java.util.List", 6 | "description": "Description for wx.miniapp.configs." 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig: http://editorconfig.org/ 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/model/Result.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | 6 | /** 7 | * Project: weixin-java-miniapp-demo 8 | * Author: jiezhi 9 | * Date: 2019-03-31 12:16 10 | * Function: 11 | */ 12 | @Data 13 | @Builder 14 | public class Result { 15 | private boolean success; 16 | private String msg; 17 | private Object obj; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/repository/AttendanceRepository.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.repository; 2 | 3 | import io.github.jiezhi.wx.miniapp.model.Attendance; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | /** 7 | * Project: weixin-java-miniapp-demo 8 | * Author: jiezhi 9 | * Date: 2019-03-31 14:43 10 | * Function: 11 | */ 12 | public interface AttendanceRepository extends CrudRepository { 13 | } 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 婚礼邀请函服务端 2 | 3 | [![Build Status](https://travis-ci.org/Jiezhi/marriage-miniapp-server.svg?branch=master)](https://travis-ci.org/Jiezhi/marriage-miniapp-server) 4 | 5 | 本项目基于 6 | binarywang的[weixin-java-miniapp-demo](https://github.com/binarywang/weixin-java-miniapp-demo) 和 hackun666的[OnceLove](https://github.com/hackun666/OnceLove)修改完成。 7 | 8 | 修改后的后端项目为[marriage-miniapp-server](https://github.com/Jiezhi/marriage-miniapp-server)和前端项目为[OnceLove](https://github.com/Jiezhi/OnceLove)。 9 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/config/StorageProperties.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | 6 | /** 7 | * Project: weixin-java-miniapp-demo 8 | * Author: jiezhi 9 | * Date: 2019-04-01 14:04 10 | * Function: 11 | */ 12 | @ConfigurationProperties("storage") 13 | @Data 14 | public class StorageProperties { 15 | private String location = "upload-dir"; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/repository/LocationRepository.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.repository; 2 | 3 | import io.github.jiezhi.wx.miniapp.model.Location; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | /** 7 | * Project: weixin-java-miniapp-demo 8 | * Author: jiezhi 9 | * Date: 2019-03-30 16:04 10 | * Function: 11 | */ 12 | public interface LocationRepository extends CrudRepository { 13 | Location getLocationByUid(int uid); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/repository/MainInfoRepository.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.repository; 2 | 3 | import io.github.jiezhi.wx.miniapp.model.MainInfo; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | /** 7 | * Project: weixin-java-miniapp-demo 8 | * Author: jiezhi 9 | * Date: 2019-03-29 12:00 10 | * Function: 11 | */ 12 | public interface MainInfoRepository extends CrudRepository { 13 | MainInfo findMainInfoByUid(int uid); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/error/StorageException.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.error; 2 | 3 | /** 4 | * Project: weixin-java-miniapp-demo 5 | * Author: jiezhi 6 | * Date: 2019-04-01 14:05 7 | * Function: 8 | */ 9 | public class StorageException extends RuntimeException { 10 | public StorageException(String message) { 11 | super(message); 12 | } 13 | 14 | public StorageException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/repository/AlbumRepository.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.repository; 2 | 3 | import io.github.jiezhi.wx.miniapp.model.Photo; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Project: weixin-java-miniapp-demo 10 | * Author: jiezhi 11 | * Date: 2019-03-30 15:32 12 | * Function: 13 | */ 14 | public interface AlbumRepository extends CrudRepository { 15 | List findAllByUid(int uid); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/repository/CommentRepository.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.repository; 2 | 3 | import io.github.jiezhi.wx.miniapp.model.Comment; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Project: weixin-java-miniapp-demo 10 | * Author: jiezhi 11 | * Date: 2019-03-30 16:20 12 | * Function: 13 | */ 14 | public interface CommentRepository extends CrudRepository { 15 | List getAllByUid(int uid); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/utils/TimeUtils.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.utils; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | /** 7 | * Project: weixin-java-miniapp-demo 8 | * Author: jiezhi 9 | * Date: 2019-03-31 22:35 10 | * Function: 11 | */ 12 | public class TimeUtils { 13 | public static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 14 | public static String getNowString() { 15 | return dateFormat.format(new Date()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 出错啦! 5 | 6 | 7 | 8 |

9 |

10 |

11 |

12 |

13 |

14 |

15 | 16 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/repository/BlessRepository.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.repository; 2 | 3 | import io.github.jiezhi.wx.miniapp.model.Bless; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Project: weixin-java-miniapp-demo 10 | * Author: jiezhi 11 | * Date: 2019-03-30 16:12 12 | * Function: 13 | */ 14 | public interface BlessRepository extends CrudRepository { 15 | List getAllByUid(int uid); 16 | boolean existsByAvatarUrl(String url); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/model/AllData.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | 9 | /** 10 | * Project: weixin-java-miniapp-demo 11 | * Author: jiezhi 12 | * Date: 2019-03-28 17:21 13 | * Function: 14 | */ 15 | @Data 16 | @Builder 17 | public class AllData implements Serializable { 18 | private MainInfo mainInfo; 19 | private Bless zanLog; 20 | private int zanNum; 21 | private List album; 22 | private String music_url; 23 | private List chatList; 24 | private int chatNum; 25 | private Location location; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/model/Location.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.GenerationType; 9 | import javax.persistence.Id; 10 | 11 | /** 12 | * Project: weixin-java-miniapp-demo 13 | * Author: jiezhi 14 | * Date: 2019-03-30 16:02 15 | * Function: 16 | */ 17 | @Data 18 | @Builder 19 | @Entity 20 | public class Location { 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.AUTO) 23 | private int id; 24 | private int uid; 25 | private double lat; 26 | private double lon; 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/model/Photo.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.GenerationType; 9 | import javax.persistence.Id; 10 | import java.io.Serializable; 11 | 12 | /** 13 | * Project: weixin-java-miniapp-demo 14 | * Author: jiezhi 15 | * Date: 2019-03-28 17:18 16 | * Function: 17 | */ 18 | @Data 19 | @Builder 20 | @Entity 21 | public class Photo implements Serializable { 22 | @Id 23 | @GeneratedValue(strategy = GenerationType.AUTO) 24 | private int id; 25 | private int uid; 26 | private String image; 27 | private String addtime; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/resources/application.yml.template: -------------------------------------------------------------------------------- 1 | debug: true 2 | logging: 3 | level: 4 | org.springframework.web: info 5 | com.github.binarywang.demo.wx.miniapp: debug 6 | cn.binarywang.wx.miniapp: debug 7 | wx: 8 | miniapp: 9 | configs: 10 | - appid: #微信小程序的appid 11 | secret: #微信小程序的Secret 12 | token: #微信小程序消息服务器配置的token 13 | aesKey: #微信小程序消息服务器配置的EncodingAESKey 14 | msgDataFormat: JSON 15 | 16 | spring: 17 | jpa: 18 | hibernate: 19 | ddl-auto: create 20 | datasource: 21 | url: jdbc:mysql://localhost:3306/db_example 22 | username: 23 | password: 24 | servlet: 25 | multipart: 26 | max-file-size: 10MB 27 | max-request-size: 10MB 28 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/storage/StorageService.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.storage; 2 | 3 | import org.springframework.core.io.Resource; 4 | import org.springframework.web.multipart.MultipartFile; 5 | 6 | import java.nio.file.Path; 7 | import java.util.stream.Stream; 8 | 9 | /** 10 | * Project: weixin-java-miniapp-demo 11 | * Author: jiezhi 12 | * Date: 2019-04-01 13:42 13 | * Function: 14 | *

15 | * Ref:https://spring.io/guides/gs/uploading-files/ 16 | */ 17 | public interface StorageService { 18 | void init(); 19 | 20 | void store(MultipartFile file); 21 | 22 | Stream loadAll(); 23 | 24 | Path load(String filename); 25 | 26 | Resource loadAsResource(String filename); 27 | 28 | void deleteAll(); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/error/ErrorController.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.error; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | 7 | /** 8 | *

 9 |  * 出错页面控制器
10 |  * Created by Binary Wang on 2018/8/25.
11 |  * 
12 | * 13 | * @author Binary Wang 14 | */ 15 | @Controller 16 | @RequestMapping("/error") 17 | public class ErrorController { 18 | 19 | @GetMapping(value = "/404") 20 | public String error404() { 21 | return "error"; 22 | } 23 | 24 | @GetMapping(value = "/500") 25 | public String error500() { 26 | return "error"; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/model/WxUser.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.model; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.GenerationType; 8 | import javax.persistence.Id; 9 | 10 | /** 11 | * Project: weixin-java-miniapp-demo 12 | * Author: jiezhi 13 | * Date: 2019-03-31 21:21 14 | * Function: 15 | */ 16 | @Data 17 | @Entity 18 | public class WxUser { 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.AUTO) 21 | private int id; 22 | private int uid; 23 | private String nickName; 24 | private String avatarUrl; 25 | private String city; 26 | private String country; 27 | private String gender; 28 | private String language; 29 | private String province; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/resources/templates/uploadForm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

5 |

6 | 7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
File to upload:
20 |
21 |
22 | 23 |
24 | 29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/model/Attendance.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.GenerationType; 9 | import javax.persistence.Id; 10 | 11 | /** 12 | * Project: weixin-java-miniapp-demo 13 | * Author: jiezhi 14 | * Date: 2019-03-31 14:41 15 | * Function: 16 | */ 17 | @Data 18 | @Entity 19 | @Builder 20 | public class Attendance { 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.AUTO) 23 | private int id; 24 | private int uid; 25 | private String appid; 26 | private String nickname; 27 | private String face; 28 | private String name; 29 | private String tel; 30 | private String plan; 31 | private String extra; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/model/Comment.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | import org.springframework.format.annotation.DateTimeFormat; 6 | 7 | import javax.persistence.Entity; 8 | import javax.persistence.GeneratedValue; 9 | import javax.persistence.GenerationType; 10 | import javax.persistence.Id; 11 | import java.io.Serializable; 12 | import java.util.Date; 13 | 14 | /** 15 | * Project: weixin-java-miniapp-demo 16 | * Author: jiezhi 17 | * Date: 2019-03-28 17:19 18 | * Function: 19 | */ 20 | @Data 21 | @Entity 22 | @Builder 23 | public class Comment implements Serializable { 24 | @Id 25 | @GeneratedValue(strategy = GenerationType.AUTO) 26 | private int id; 27 | private int uid; 28 | private String nickname; 29 | private String face; 30 | private String words; 31 | private String time; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/error/ErrorPageConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.error; 2 | 3 | import org.springframework.boot.web.server.ErrorPage; 4 | import org.springframework.boot.web.server.ErrorPageRegistrar; 5 | import org.springframework.boot.web.server.ErrorPageRegistry; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | *
11 |  * 配置错误状态与对应访问路径
12 |  * Created by Binary Wang on 2018/8/25.
13 |  * 
14 | * 15 | * @author
Binary Wang 16 | */ 17 | @Component 18 | public class ErrorPageConfiguration implements ErrorPageRegistrar { 19 | @Override 20 | public void registerErrorPages(ErrorPageRegistry errorPageRegistry) { 21 | errorPageRegistry.addErrorPages( 22 | new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"), 23 | new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500") 24 | ); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.utils; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.fasterxml.jackson.databind.SerializationFeature; 7 | 8 | /** 9 | * @author Binary Wang 10 | */ 11 | public class JsonUtils { 12 | private static final ObjectMapper JSON = new ObjectMapper(); 13 | 14 | static { 15 | JSON.setSerializationInclusion(Include.NON_NULL); 16 | JSON.configure(SerializationFeature.INDENT_OUTPUT, Boolean.TRUE); 17 | } 18 | 19 | public static String toJson(Object obj) { 20 | try { 21 | return JSON.writeValueAsString(obj); 22 | } catch (JsonProcessingException e) { 23 | e.printStackTrace(); 24 | } 25 | 26 | return null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/config/WxMaProperties.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.config; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | 7 | import lombok.Data; 8 | 9 | /** 10 | * @author Binary Wang 11 | */ 12 | @Data 13 | @ConfigurationProperties(prefix = "wx.miniapp") 14 | public class WxMaProperties { 15 | 16 | private List configs; 17 | 18 | @Data 19 | public static class Config { 20 | /** 21 | * 设置微信小程序的appid 22 | */ 23 | private String appid; 24 | 25 | /** 26 | * 设置微信小程序的Secret 27 | */ 28 | private String secret; 29 | 30 | /** 31 | * 设置微信小程序消息服务器配置的token 32 | */ 33 | private String token; 34 | 35 | /** 36 | * 设置微信小程序消息服务器配置的EncodingAESKey 37 | */ 38 | private String aesKey; 39 | 40 | /** 41 | * 消息格式,XML或者JSON 42 | */ 43 | private String msgDataFormat; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/model/Bless.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import org.springframework.format.annotation.DateTimeFormat; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | import javax.persistence.Entity; 10 | import javax.persistence.GeneratedValue; 11 | import javax.persistence.GenerationType; 12 | import javax.persistence.Id; 13 | import java.io.Serializable; 14 | import java.util.Date; 15 | 16 | /** 17 | * Project: weixin-java-miniapp-demo 18 | * Author: jiezhi 19 | * Date: 2019-03-28 17:17 20 | * Function: 21 | */ 22 | @Data 23 | @Builder 24 | @Entity 25 | public class Bless implements Serializable { 26 | @Id 27 | @GeneratedValue(strategy = GenerationType.AUTO) 28 | private int id; 29 | private int uid; 30 | private String openid; 31 | private String time; 32 | private String nickName; 33 | private String avatarUrl; 34 | private String city; 35 | private String country; 36 | private String gender; 37 | private String language; 38 | private String province; 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/model/MainInfo.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.model; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | import org.hibernate.validator.constraints.UniqueElements; 6 | 7 | import javax.persistence.Entity; 8 | import javax.persistence.GeneratedValue; 9 | import javax.persistence.GenerationType; 10 | import javax.persistence.Id; 11 | import java.io.Serializable; 12 | import java.util.Date; 13 | 14 | /** 15 | * Project: weixin-java-miniapp-demo 16 | * Author: jiezhi 17 | * Date: 2019-03-28 17:11 18 | * Function: 19 | */ 20 | @Data 21 | @Builder 22 | @Entity 23 | public class MainInfo implements Serializable { 24 | @Id 25 | @GeneratedValue(strategy = GenerationType.AUTO) 26 | private int id; 27 | // @UniqueElements 28 | private int uid; 29 | private String appid; 30 | private String app_name; 31 | private String he; 32 | private String she; 33 | private String he_tel; 34 | private String she_tel; 35 | private String date; 36 | private String lunar; 37 | private String music; 38 | private String address; 39 | private String hotel; 40 | private double lat; 41 | private double lng; 42 | private String share; 43 | private String cover; 44 | private String qrimg; 45 | private String thumb; 46 | private String code; 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/WxMaDemoApplication.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp; 2 | 3 | import io.github.jiezhi.wx.miniapp.config.StorageProperties; 4 | import io.github.jiezhi.wx.miniapp.model.*; 5 | import io.github.jiezhi.wx.miniapp.repository.*; 6 | import io.github.jiezhi.wx.miniapp.storage.StorageService; 7 | import io.github.jiezhi.wx.miniapp.utils.TimeUtils; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.boot.CommandLineRunner; 11 | import org.springframework.boot.SpringApplication; 12 | import org.springframework.boot.autoconfigure.SpringBootApplication; 13 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 14 | import org.springframework.context.annotation.Bean; 15 | 16 | import java.util.Date; 17 | 18 | /** 19 | * @author Binary Wang 20 | */ 21 | @SpringBootApplication 22 | @EnableConfigurationProperties(StorageProperties.class) 23 | public class WxMaDemoApplication { 24 | private static final Logger logger = LoggerFactory.getLogger(WxMaDemoApplication.class); 25 | 26 | public static void main(String[] args) { 27 | SpringApplication.run(WxMaDemoApplication.class, args); 28 | } 29 | 30 | @Bean 31 | CommandLineRunner init(StorageService storageService) { 32 | return (args) -> { 33 | storageService.deleteAll(); 34 | storageService.init(); 35 | }; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/controller/FileController.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.controller; 2 | 3 | import io.github.jiezhi.wx.miniapp.error.StorageException; 4 | import io.github.jiezhi.wx.miniapp.storage.StorageService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.core.io.Resource; 7 | import org.springframework.http.HttpHeaders; 8 | import org.springframework.http.MediaType; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.ui.Model; 12 | import org.springframework.web.bind.annotation.*; 13 | import org.springframework.web.multipart.MultipartFile; 14 | import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; 15 | import org.springframework.web.servlet.mvc.support.RedirectAttributes; 16 | 17 | import java.io.IOException; 18 | import java.util.stream.Collector; 19 | import java.util.stream.Collectors; 20 | 21 | /** 22 | * Project: weixin-java-miniapp-demo 23 | * Author: jiezhi 24 | * Date: 2019-04-01 13:41 25 | * Function: 26 | *

27 | * Ref: https://spring.io/guides/gs/uploading-files/ 28 | */ 29 | @Controller 30 | public class FileController { 31 | private final StorageService storageService; 32 | 33 | @Autowired 34 | public FileController(StorageService service) { 35 | this.storageService = service; 36 | } 37 | 38 | @GetMapping("/upload") 39 | public String listUploadedFiles(Model model) throws IOException { 40 | model.addAttribute("files", storageService 41 | .loadAll() 42 | .map(path -> 43 | MvcUriComponentsBuilder.fromMethodName( 44 | FileController.class, "serveFile", path.getFileName().toString() 45 | ) 46 | .build().toString() 47 | ) 48 | .collect(Collectors.toList())); 49 | return "uploadForm"; 50 | } 51 | 52 | @GetMapping("/upload/files/{filename:.+}") 53 | @ResponseBody 54 | public ResponseEntity serveFile(@PathVariable String filename) { 55 | Resource file = storageService.loadAsResource(filename); 56 | return ResponseEntity 57 | .ok() 58 | .header(HttpHeaders.CONTENT_DISPOSITION, "attachement; filename=\"" + file.getFilename() + "\"") 59 | .contentType(MediaType.IMAGE_JPEG) 60 | .body(file); 61 | } 62 | 63 | @PostMapping("/upload") 64 | public String handleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) { 65 | storageService.store(file); 66 | redirectAttributes.addFlashAttribute("message", "You successfully uploaded " + file.getOriginalFilename() + "!"); 67 | return "redirect:/upload"; 68 | } 69 | 70 | @ExceptionHandler(StorageException.class) 71 | public ResponseEntity handleStorageFileNotFound(StorageService exc) { 72 | return ResponseEntity.notFound().build(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /init.sql: -------------------------------------------------------------------------------- 1 | # Automatically generated by jpa 2 | CREATE TABLE attendance 3 | ( 4 | id INT NOT NULL 5 | PRIMARY KEY, 6 | appid VARCHAR(255) NULL, 7 | extra VARCHAR(255) NULL, 8 | face VARCHAR(255) NULL, 9 | name VARCHAR(255) NULL, 10 | nickname VARCHAR(255) NULL, 11 | plan VARCHAR(255) NULL, 12 | tel VARCHAR(255) NULL, 13 | uid INT NOT NULL 14 | ) 15 | ENGINE = MyISAM; 16 | 17 | CREATE TABLE bless 18 | ( 19 | id INT NOT NULL 20 | PRIMARY KEY, 21 | avatar_url VARCHAR(255) NULL, 22 | city VARCHAR(255) NULL, 23 | country VARCHAR(255) NULL, 24 | gender VARCHAR(255) NULL, 25 | language VARCHAR(255) NULL, 26 | nick_name VARCHAR(255) NULL, 27 | openid VARCHAR(255) NULL, 28 | province VARCHAR(255) NULL, 29 | time VARCHAR(255) NULL, 30 | uid INT NOT NULL 31 | ) 32 | ENGINE = MyISAM; 33 | 34 | CREATE TABLE comment 35 | ( 36 | id INT NOT NULL 37 | PRIMARY KEY, 38 | face VARCHAR(255) NULL, 39 | nickname VARCHAR(255) NULL, 40 | time VARCHAR(255) NULL, 41 | uid INT NOT NULL, 42 | words VARCHAR(255) NULL 43 | ) 44 | ENGINE = MyISAM; 45 | 46 | CREATE TABLE hibernate_sequence 47 | ( 48 | next_val BIGINT NULL 49 | ) 50 | ENGINE = MyISAM; 51 | 52 | CREATE TABLE location 53 | ( 54 | id INT NOT NULL 55 | PRIMARY KEY, 56 | lat DOUBLE NOT NULL, 57 | lon DOUBLE NOT NULL, 58 | uid INT NOT NULL 59 | ) 60 | ENGINE = MyISAM; 61 | 62 | CREATE TABLE main_info 63 | ( 64 | id INT NOT NULL 65 | PRIMARY KEY, 66 | address VARCHAR(255) NULL, 67 | app_name VARCHAR(255) NULL, 68 | appid VARCHAR(255) NULL, 69 | code VARCHAR(255) NULL, 70 | cover VARCHAR(255) NULL, 71 | date VARCHAR(255) NULL, 72 | he VARCHAR(255) NULL, 73 | he_tel VARCHAR(255) NULL, 74 | hotel VARCHAR(255) NULL, 75 | lat DOUBLE NOT NULL, 76 | lng DOUBLE NOT NULL, 77 | lunar VARCHAR(255) NULL, 78 | music VARCHAR(255) NULL, 79 | qrimg VARCHAR(255) NULL, 80 | share VARCHAR(255) NULL, 81 | she VARCHAR(255) NULL, 82 | she_tel VARCHAR(255) NULL, 83 | thumb VARCHAR(255) NULL, 84 | uid INT NOT NULL 85 | ) 86 | ENGINE = MyISAM; 87 | 88 | CREATE TABLE photo 89 | ( 90 | id INT NOT NULL 91 | PRIMARY KEY, 92 | addtime VARCHAR(255) NULL, 93 | image VARCHAR(255) NULL, 94 | uid INT NOT NULL 95 | ) 96 | ENGINE = MyISAM; 97 | 98 | CREATE TABLE wx_user 99 | ( 100 | id INT NOT NULL 101 | PRIMARY KEY, 102 | avatar_url VARCHAR(255) NULL, 103 | city VARCHAR(255) NULL, 104 | country VARCHAR(255) NULL, 105 | gender VARCHAR(255) NULL, 106 | language VARCHAR(255) NULL, 107 | nick_name VARCHAR(255) NULL, 108 | province VARCHAR(255) NULL, 109 | uid INT NOT NULL 110 | ) 111 | ENGINE = MyISAM; 112 | 113 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/controller/WxMaUserController.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.controller; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | import cn.binarywang.wx.miniapp.api.WxMaService; 12 | import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; 13 | import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; 14 | import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; 15 | import io.github.jiezhi.wx.miniapp.config.WxMaConfiguration; 16 | import io.github.jiezhi.wx.miniapp.utils.JsonUtils; 17 | import me.chanjar.weixin.common.error.WxErrorException; 18 | 19 | /** 20 | * 微信小程序用户接口 21 | * 22 | * @author Binary Wang 23 | */ 24 | @RestController 25 | @RequestMapping("/wx/user/{appid}") 26 | public class WxMaUserController { 27 | private final Logger logger = LoggerFactory.getLogger(this.getClass()); 28 | 29 | /** 30 | * 登陆接口 31 | */ 32 | @GetMapping("/login") 33 | public String login(@PathVariable String appid, String code) { 34 | if (StringUtils.isBlank(code)) { 35 | return "empty jscode"; 36 | } 37 | 38 | final WxMaService wxService = WxMaConfiguration.getMaService(appid); 39 | 40 | try { 41 | WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code); 42 | this.logger.info(session.getSessionKey()); 43 | this.logger.info(session.getOpenid()); 44 | //TODO 可以增加自己的逻辑,关联业务相关数据 45 | return JsonUtils.toJson(session); 46 | } catch (WxErrorException e) { 47 | this.logger.error(e.getMessage(), e); 48 | return e.toString(); 49 | } 50 | } 51 | 52 | /** 53 | *

54 |      * 获取用户信息接口
55 |      * 
56 | */ 57 | @GetMapping("/info") 58 | public String info(@PathVariable String appid, String sessionKey, 59 | String signature, String rawData, String encryptedData, String iv) { 60 | final WxMaService wxService = WxMaConfiguration.getMaService(appid); 61 | 62 | // 用户信息校验 63 | if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) { 64 | return "user check failed"; 65 | } 66 | 67 | // 解密用户信息 68 | WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(sessionKey, encryptedData, iv); 69 | 70 | return JsonUtils.toJson(userInfo); 71 | } 72 | 73 | /** 74 | *
75 |      * 获取用户绑定手机号信息
76 |      * 
77 | */ 78 | @GetMapping("/phone") 79 | public String phone(@PathVariable String appid, String sessionKey, String signature, 80 | String rawData, String encryptedData, String iv) { 81 | final WxMaService wxService = WxMaConfiguration.getMaService(appid); 82 | 83 | // 用户信息校验 84 | if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) { 85 | return "user check failed"; 86 | } 87 | 88 | // 解密 89 | WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv); 90 | 91 | return JsonUtils.toJson(phoneNoInfo); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/controller/WxMaMediaController.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.controller; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | import javax.servlet.http.HttpServletRequest; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.PathVariable; 13 | import org.springframework.web.bind.annotation.PostMapping; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RestController; 16 | import org.springframework.web.multipart.MultipartFile; 17 | import org.springframework.web.multipart.MultipartHttpServletRequest; 18 | import org.springframework.web.multipart.commons.CommonsMultipartResolver; 19 | 20 | import cn.binarywang.wx.miniapp.api.WxMaService; 21 | import cn.binarywang.wx.miniapp.constant.WxMaConstants; 22 | import io.github.jiezhi.wx.miniapp.config.WxMaConfiguration; 23 | import com.google.common.collect.Lists; 24 | import com.google.common.io.Files; 25 | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; 26 | import me.chanjar.weixin.common.error.WxErrorException; 27 | 28 | /** 29 | *
30 |  *  小程序临时素材接口
31 |  *  Created by BinaryWang on 2017/6/16.
32 |  * 
33 | * 34 | * @author Binary Wang 35 | */ 36 | @RestController 37 | @RequestMapping("/wx/media/{appid}") 38 | public class WxMaMediaController { 39 | private final Logger logger = LoggerFactory.getLogger(this.getClass()); 40 | 41 | /** 42 | * 上传临时素材 43 | * 44 | * @return 素材的media_id列表,实际上如果有的话,只会有一个 45 | */ 46 | @PostMapping("/upload") 47 | public List uploadMedia(@PathVariable String appid, HttpServletRequest request) throws WxErrorException { 48 | final WxMaService wxService = WxMaConfiguration.getMaService(appid); 49 | 50 | CommonsMultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext()); 51 | 52 | if (!resolver.isMultipart(request)) { 53 | return Lists.newArrayList(); 54 | } 55 | 56 | MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request; 57 | Iterator it = multiRequest.getFileNames(); 58 | List result = Lists.newArrayList(); 59 | while (it.hasNext()) { 60 | try { 61 | MultipartFile file = multiRequest.getFile(it.next()); 62 | File newFile = new File(Files.createTempDir(), file.getOriginalFilename()); 63 | this.logger.info("filePath is :" + newFile.toString()); 64 | file.transferTo(newFile); 65 | WxMediaUploadResult uploadResult = wxService.getMediaService().uploadMedia(WxMaConstants.KefuMsgType.IMAGE, newFile); 66 | this.logger.info("media_id : " + uploadResult.getMediaId()); 67 | result.add(uploadResult.getMediaId()); 68 | } catch (IOException e) { 69 | this.logger.error(e.getMessage(), e); 70 | } 71 | } 72 | 73 | return result; 74 | } 75 | 76 | /** 77 | * 下载临时素材 78 | */ 79 | @GetMapping("/download/{mediaId}") 80 | public File getMedia(@PathVariable String appid, @PathVariable String mediaId) throws WxErrorException { 81 | final WxMaService wxService = WxMaConfiguration.getMaService(appid); 82 | 83 | return wxService.getMediaService().getMedia(mediaId); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/service/FileSystemStorageService.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.service; 2 | 3 | import io.github.jiezhi.wx.miniapp.config.StorageProperties; 4 | import io.github.jiezhi.wx.miniapp.error.StorageException; 5 | import io.github.jiezhi.wx.miniapp.storage.StorageService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.core.io.Resource; 8 | import org.springframework.core.io.UrlResource; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.util.FileSystemUtils; 11 | import org.springframework.util.StringUtils; 12 | import org.springframework.web.multipart.MultipartFile; 13 | 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.net.MalformedURLException; 17 | import java.nio.file.Files; 18 | import java.nio.file.Path; 19 | import java.nio.file.Paths; 20 | import java.nio.file.StandardCopyOption; 21 | import java.util.stream.Stream; 22 | 23 | /** 24 | * Project: weixin-java-miniapp-demo 25 | * Author: jiezhi 26 | * Date: 2019-04-01 14:09 27 | * Function: 28 | */ 29 | @Service 30 | public class FileSystemStorageService implements StorageService { 31 | private final Path rootLocation; 32 | 33 | @Autowired 34 | public FileSystemStorageService(StorageProperties properties) { 35 | this.rootLocation = Paths.get(properties.getLocation()); 36 | } 37 | 38 | @Override 39 | public void init() { 40 | try { 41 | Files.createDirectories(rootLocation); 42 | } catch (IOException e) { 43 | throw new StorageException("Could not initialize storage", e); 44 | } 45 | } 46 | 47 | @Override 48 | public void store(MultipartFile file) { 49 | String filename = StringUtils.cleanPath(file.getOriginalFilename()); 50 | try { 51 | if (file.isEmpty()) { 52 | throw new StorageException("Failed to store empty file " + filename); 53 | } 54 | if (filename.contains("..")) { 55 | throw new StorageException("Cannot store file with relative path outside current directroy " + filename); 56 | } 57 | try (InputStream inputStream = file.getInputStream()) { 58 | Files.copy(inputStream, this.rootLocation.resolve(filename), StandardCopyOption.REPLACE_EXISTING); 59 | } 60 | } catch (IOException e) { 61 | throw new StorageException("Failed to store file " + filename); 62 | } 63 | } 64 | 65 | @Override 66 | public Stream loadAll() { 67 | try { 68 | return Files.walk(this.rootLocation, 1) 69 | .filter(path -> !path.equals(this.rootLocation)) 70 | .map(this.rootLocation::relativize); 71 | } catch (IOException e) { 72 | throw new StorageException("Failed to read stored files", e); 73 | } 74 | } 75 | 76 | @Override 77 | public Path load(String filename) { 78 | return rootLocation.resolve(filename); 79 | } 80 | 81 | @Override 82 | public Resource loadAsResource(String filename) { 83 | try { 84 | Path file = load(filename); 85 | Resource resource = new UrlResource(file.toUri()); 86 | if (resource.exists() || resource.isReadable()) { 87 | return resource; 88 | } else { 89 | throw new StorageException("Could not read file:" + filename); 90 | } 91 | } catch (MalformedURLException e) { 92 | throw new StorageException("Could not read file: " + filename, e); 93 | } 94 | } 95 | 96 | @Override 97 | public void deleteAll() { 98 | FileSystemUtils.deleteRecursively(rootLocation.toFile()); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/controller/WxPortalController.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.controller; 2 | 3 | import java.util.Objects; 4 | 5 | import org.apache.commons.lang3.StringUtils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestParam; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | import cn.binarywang.wx.miniapp.api.WxMaService; 17 | import cn.binarywang.wx.miniapp.bean.WxMaMessage; 18 | import cn.binarywang.wx.miniapp.constant.WxMaConstants; 19 | import io.github.jiezhi.wx.miniapp.config.WxMaConfiguration; 20 | 21 | /** 22 | * @author Binary Wang 23 | */ 24 | @RestController 25 | @RequestMapping("/wx/portal/{appid}") 26 | public class WxPortalController { 27 | private final Logger logger = LoggerFactory.getLogger(this.getClass()); 28 | 29 | @GetMapping(produces = "text/plain;charset=utf-8") 30 | public String authGet(@PathVariable String appid, 31 | @RequestParam(name = "signature", required = false) String signature, 32 | @RequestParam(name = "timestamp", required = false) String timestamp, 33 | @RequestParam(name = "nonce", required = false) String nonce, 34 | @RequestParam(name = "echostr", required = false) String echostr) { 35 | this.logger.info("\n接收到来自微信服务器的认证消息:signature = [{}], timestamp = [{}], nonce = [{}], echostr = [{}]", 36 | signature, timestamp, nonce, echostr); 37 | 38 | if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) { 39 | throw new IllegalArgumentException("请求参数非法,请核实!"); 40 | } 41 | 42 | final WxMaService wxService = WxMaConfiguration.getMaService(appid); 43 | 44 | if (wxService.checkSignature(timestamp, nonce, signature)) { 45 | return echostr; 46 | } 47 | 48 | return "非法请求"; 49 | } 50 | 51 | @PostMapping(produces = "application/xml; charset=UTF-8") 52 | public String post(@PathVariable String appid, 53 | @RequestBody String requestBody, 54 | @RequestParam("msg_signature") String msgSignature, 55 | @RequestParam("encrypt_type") String encryptType, 56 | @RequestParam("signature") String signature, 57 | @RequestParam("timestamp") String timestamp, 58 | @RequestParam("nonce") String nonce) { 59 | this.logger.info("\n接收微信请求:[msg_signature=[{}], encrypt_type=[{}], signature=[{}]," + 60 | " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", 61 | msgSignature, encryptType, signature, timestamp, nonce, requestBody); 62 | 63 | final WxMaService wxService = WxMaConfiguration.getMaService(appid); 64 | 65 | final boolean isJson = Objects.equals(wxService.getWxMaConfig().getMsgDataFormat(), 66 | WxMaConstants.MsgDataFormat.JSON); 67 | if (StringUtils.isBlank(encryptType)) { 68 | // 明文传输的消息 69 | WxMaMessage inMessage; 70 | if (isJson) { 71 | inMessage = WxMaMessage.fromJson(requestBody); 72 | } else {//xml 73 | inMessage = WxMaMessage.fromXml(requestBody); 74 | } 75 | 76 | this.route(inMessage,appid); 77 | return "success"; 78 | } 79 | 80 | if ("aes".equals(encryptType)) { 81 | // 是aes加密的消息 82 | WxMaMessage inMessage; 83 | if (isJson) { 84 | inMessage = WxMaMessage.fromEncryptedJson(requestBody, wxService.getWxMaConfig()); 85 | } else {//xml 86 | inMessage = WxMaMessage.fromEncryptedXml(requestBody, wxService.getWxMaConfig(), 87 | timestamp, nonce, msgSignature); 88 | } 89 | 90 | this.route(inMessage, appid); 91 | return "success"; 92 | } 93 | 94 | throw new RuntimeException("不可识别的加密类型:" + encryptType); 95 | } 96 | 97 | private void route(WxMaMessage message, String appid) { 98 | try { 99 | WxMaConfiguration.getRouters().get(appid).route(message); 100 | } catch (Exception e) { 101 | this.logger.error(e.getMessage(), e); 102 | } 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/controller/AppController.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.controller; 2 | 3 | import io.github.jiezhi.wx.miniapp.model.*; 4 | import io.github.jiezhi.wx.miniapp.repository.*; 5 | import io.github.jiezhi.wx.miniapp.utils.TimeUtils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | import java.io.BufferedReader; 12 | import java.io.File; 13 | import java.io.FileReader; 14 | import java.io.IOException; 15 | import java.util.Date; 16 | import java.util.List; 17 | 18 | /** 19 | * Project: weixin-java-miniapp-demo 20 | * Author: jiezhi 21 | * Date: 2019-03-28 16:56 22 | * Function: 23 | */ 24 | @RestController 25 | @RequestMapping(path = "/wx") 26 | public class AppController { 27 | 28 | private final Logger logger = LoggerFactory.getLogger(AppController.class); 29 | 30 | @Autowired 31 | private MainInfoRepository infoRepository; 32 | 33 | @Autowired 34 | private AlbumRepository albumRepository; 35 | 36 | @Autowired 37 | private LocationRepository locationRepository; 38 | 39 | @Autowired 40 | private BlessRepository blessRepository; 41 | 42 | @Autowired 43 | private CommentRepository commentRepository; 44 | 45 | @Autowired 46 | private AttendanceRepository attendanceRepository; 47 | 48 | @GetMapping("/") 49 | public String getInfo(@RequestParam String c, @RequestParam String appid) { 50 | File file = new File("/Users/jiezhi/Documents/gooddemo/weixin-java-miniapp-demo/data.json"); 51 | try { 52 | String data = new BufferedReader(new FileReader(file)).readLine(); 53 | return data; 54 | } catch (IOException e) { 55 | e.printStackTrace(); 56 | } 57 | return "{\"hello\": \"world\"}"; 58 | } 59 | 60 | @GetMapping("/info") 61 | public @ResponseBody 62 | MainInfo getInfo(@RequestParam int uid) { 63 | return infoRepository.findMainInfoByUid(uid); 64 | } 65 | 66 | @GetMapping("/album") 67 | public @ResponseBody 68 | List getAlbumList(@RequestParam int uid) { 69 | return albumRepository.findAllByUid(uid); 70 | } 71 | 72 | @GetMapping("/map") 73 | public @ResponseBody 74 | AllData getLocation(@RequestParam int uid) { 75 | MainInfo mainInfo = infoRepository.findMainInfoByUid(uid); 76 | 77 | Location location = locationRepository.getLocationByUid(uid); 78 | return AllData.builder() 79 | .mainInfo(mainInfo) 80 | .location(location) 81 | .build(); 82 | } 83 | 84 | @GetMapping("/bless") 85 | public @ResponseBody 86 | List getBlesses(@RequestParam int uid) { 87 | return blessRepository.getAllByUid(uid); 88 | } 89 | 90 | @PostMapping("/bless") 91 | public @ResponseBody 92 | Result postBless(@RequestBody Bless bless) { 93 | logger.debug(bless.toString()); 94 | 95 | if (blessRepository.existsByAvatarUrl(bless.getAvatarUrl())) { 96 | logger.debug("already blessed"); 97 | return Result.builder() 98 | .msg("您已经送过祝福啦") 99 | .success(false) 100 | .build(); 101 | } 102 | bless.setTime(TimeUtils.dateFormat.format(new Date())); 103 | blessRepository.save(bless); 104 | 105 | List blesses = blessRepository.getAllByUid(bless.getUid()); 106 | 107 | return Result 108 | .builder() 109 | .success(true) 110 | .msg("感谢您的祝福") 111 | .obj(blesses) 112 | .build(); 113 | } 114 | 115 | @GetMapping("/comment") 116 | public @ResponseBody 117 | List getComments(@RequestParam int uid) { 118 | return commentRepository.getAllByUid(uid); 119 | } 120 | 121 | @PostMapping("/comment") 122 | public @ResponseBody 123 | Result postComment(@RequestBody Comment comment) { 124 | // public @ResponseBody List postComment(@RequestBody Comment comment){ 125 | logger.debug(comment.toString()); 126 | comment.setTime(TimeUtils.dateFormat.format(new Date())); 127 | commentRepository.save(comment); 128 | return Result.builder() 129 | .success(true) 130 | .msg("感谢您的祝福") 131 | .obj(commentRepository.getAllByUid(comment.getUid())) 132 | .build(); 133 | } 134 | 135 | @PostMapping("/comment/submit") 136 | public @ResponseBody 137 | Result submit(@RequestBody Attendance attendance) { 138 | logger.debug(attendance.toString()); 139 | attendanceRepository.save(attendance); 140 | return Result.builder() 141 | .success(true) 142 | .msg("期待您的到来") 143 | .build(); 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.0.4.RELEASE 10 | 11 | 12 | io.github.jiezhi 13 | 1.0.0-${profiles.active} 14 | weixin-java-miniapp-love 15 | jar 16 | 17 | spring-boot-demo-for-wechat-miniapp 18 | Spring Boot Demo with wechat miniapp 19 | 20 | 21 | 3.3.0 22 | 23 | 1.8 24 | 1.8 25 | UTF-8 26 | UTF-8 27 | zh_CN 28 | wx-miniapp-demo 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-web 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-thymeleaf 39 | 40 | 41 | com.github.binarywang 42 | weixin-java-miniapp 43 | ${weixin-java-miniapp.version} 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-data-jpa 49 | 50 | 51 | 52 | mysql 53 | mysql-connector-java 54 | 55 | 62 | 63 | 64 | commons-fileupload 65 | commons-fileupload 66 | 1.3.3 67 | 68 | 69 | 70 | 71 | org.springframework.boot 72 | spring-boot-starter-test 73 | test 74 | 75 | 76 | 77 | org.projectlombok 78 | lombok 79 | provided 80 | 81 | 82 | 83 | 84 | 85 | prod 86 | 87 | prod 88 | 89 | 90 | 91 | 92 | local 93 | 94 | local 95 | 96 | 97 | true 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | src/main/resources 106 | true 107 | 108 | *.template 109 | 110 | 111 | 112 | 113 | src/main/resources 114 | true 115 | 116 | application-${profiles.active}.yml 117 | 118 | 119 | 120 | 121 | 122 | org.springframework.boot 123 | spring-boot-maven-plugin 124 | 125 | 126 | 127 | com.spotify 128 | docker-maven-plugin 129 | 1.0.0 130 | 131 | ${docker.image.prefix}/${project.artifactId} 132 | src/main/docker 133 | 134 | 135 | / 136 | ${project.build.directory} 137 | ${project.build.finalName}.jar 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /src/main/java/io/github/jiezhi/wx/miniapp/config/WxMaConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.github.jiezhi.wx.miniapp.config; 2 | 3 | import java.io.File; 4 | import java.util.Map; 5 | import java.util.stream.Collectors; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | import cn.binarywang.wx.miniapp.api.WxMaService; 13 | import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; 14 | import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; 15 | import cn.binarywang.wx.miniapp.bean.WxMaTemplateData; 16 | import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; 17 | import cn.binarywang.wx.miniapp.config.WxMaInMemoryConfig; 18 | import cn.binarywang.wx.miniapp.message.WxMaMessageHandler; 19 | import cn.binarywang.wx.miniapp.message.WxMaMessageRouter; 20 | import com.google.common.collect.Lists; 21 | import com.google.common.collect.Maps; 22 | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; 23 | import me.chanjar.weixin.common.error.WxErrorException; 24 | 25 | /** 26 | * @author Binary Wang 27 | */ 28 | @Configuration 29 | @EnableConfigurationProperties(WxMaProperties.class) 30 | public class WxMaConfiguration { 31 | private final WxMaMessageHandler templateMsgHandler = (wxMessage, context, service, sessionManager) -> 32 | service.getMsgService().sendTemplateMsg(WxMaTemplateMessage.builder() 33 | .templateId("此处更换为自己的模板id") 34 | .formId("自己替换可用的formid") 35 | .data(Lists.newArrayList( 36 | new WxMaTemplateData("keyword1", "339208499", "#173177"))) 37 | .toUser(wxMessage.getFromUser()) 38 | .build()); 39 | 40 | private final WxMaMessageHandler logHandler = (wxMessage, context, service, sessionManager) -> { 41 | System.out.println("收到消息:" + wxMessage.toString()); 42 | service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson()) 43 | .toUser(wxMessage.getFromUser()).build()); 44 | }; 45 | 46 | private final WxMaMessageHandler textHandler = (wxMessage, context, service, sessionManager) -> 47 | service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息") 48 | .toUser(wxMessage.getFromUser()).build()); 49 | 50 | private final WxMaMessageHandler picHandler = (wxMessage, context, service, sessionManager) -> { 51 | try { 52 | WxMediaUploadResult uploadResult = service.getMediaService() 53 | .uploadMedia("image", "png", 54 | ClassLoader.getSystemResourceAsStream("tmp.png")); 55 | service.getMsgService().sendKefuMsg( 56 | WxMaKefuMessage 57 | .newImageBuilder() 58 | .mediaId(uploadResult.getMediaId()) 59 | .toUser(wxMessage.getFromUser()) 60 | .build()); 61 | } catch (WxErrorException e) { 62 | e.printStackTrace(); 63 | } 64 | }; 65 | 66 | private final WxMaMessageHandler qrcodeHandler = (wxMessage, context, service, sessionManager) -> { 67 | try { 68 | final File file = service.getQrcodeService().createQrcode("123", 430); 69 | WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia("image", file); 70 | service.getMsgService().sendKefuMsg( 71 | WxMaKefuMessage 72 | .newImageBuilder() 73 | .mediaId(uploadResult.getMediaId()) 74 | .toUser(wxMessage.getFromUser()) 75 | .build()); 76 | } catch (WxErrorException e) { 77 | e.printStackTrace(); 78 | } 79 | }; 80 | 81 | private WxMaProperties properties; 82 | 83 | private static Map routers = Maps.newHashMap(); 84 | private static Map maServices = Maps.newHashMap(); 85 | 86 | @Autowired 87 | public WxMaConfiguration(WxMaProperties properties) { 88 | this.properties = properties; 89 | } 90 | 91 | public static Map getRouters() { 92 | return routers; 93 | } 94 | 95 | public static WxMaService getMaService(String appid) { 96 | WxMaService wxService = maServices.get(appid); 97 | if (wxService == null) { 98 | throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid)); 99 | } 100 | 101 | return wxService; 102 | } 103 | 104 | @Bean 105 | public Object services() { 106 | maServices = this.properties.getConfigs() 107 | .stream() 108 | .map(a -> { 109 | WxMaInMemoryConfig config = new WxMaInMemoryConfig(); 110 | config.setAppid(a.getAppid()); 111 | config.setSecret(a.getSecret()); 112 | config.setToken(a.getToken()); 113 | config.setAesKey(a.getAesKey()); 114 | config.setMsgDataFormat(a.getMsgDataFormat()); 115 | 116 | WxMaService service = new WxMaServiceImpl(); 117 | service.setWxMaConfig(config); 118 | routers.put(a.getAppid(), this.newRouter(service)); 119 | return service; 120 | }).collect(Collectors.toMap(s -> s.getWxMaConfig().getAppid(), a -> a)); 121 | 122 | return Boolean.TRUE; 123 | } 124 | 125 | private WxMaMessageRouter newRouter(WxMaService service) { 126 | final WxMaMessageRouter router = new WxMaMessageRouter(service); 127 | router 128 | .rule().handler(logHandler).next() 129 | .rule().async(false).content("模板").handler(templateMsgHandler).end() 130 | .rule().async(false).content("文本").handler(textHandler).end() 131 | .rule().async(false).content("图片").handler(picHandler).end() 132 | .rule().async(false).content("二维码").handler(qrcodeHandler).end(); 133 | return router; 134 | } 135 | 136 | } 137 | --------------------------------------------------------------------------------