1. CREATE TABLE `mmall_user` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT COMMENT \'用户表id\',
  3. `username` varchar(50) NOT NULL COMMENT \'用户名\',
  4. `password` varchar(50) NOT NULL COMMENT \'用户密码,MD5加密\',
  5. `email` varchar(50) DEFAULT NULL,
  6. `phone` varchar(20) DEFAULT NULL,
  7. `question` varchar(100) DEFAULT NULL COMMENT \'找回密码问题\',
  8. `answer` varchar(100) DEFAULT NULL COMMENT \'找回密码答案\',
  9. `role` int(4) NOT NULL COMMENT \'角色0-管理员,1-普通用户\',
  10. `create_time` datetime NOT NULL COMMENT \'创建时间\',
  11. `update_time` datetime NOT NULL COMMENT \'最后一次更新时间\',
  12. PRIMARY KEY (`id`),
  13. UNIQUE KEY `user_name_unique` (`username`) USING BTREE
  14. ) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;
  1. CREATE TABLE `mmall_order_item` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT COMMENT \'订单子表id\',
  3. `user_id` int(11) DEFAULT NULL,
  4. `order_no` bigint(20) DEFAULT NULL,
  5. `product_id` int(11) DEFAULT NULL COMMENT \'商品id\',
  6. `product_name` varchar(100) DEFAULT NULL COMMENT \'商品名称\',
  7. `product_image` varchar(500) DEFAULT NULL COMMENT \'商品图片地址\',
  8. `current_unit_price` decimal(20,2) DEFAULT NULL COMMENT \'生成订单时的商品单价,单位是元,保留两位小数\',
  9. `quantity` int(10) DEFAULT NULL COMMENT \'商品数量\',
  10. `total_price` decimal(20,2) DEFAULT NULL COMMENT \'商品总价,单位是元,保留两位小数\',
  11. `create_time` datetime DEFAULT NULL,
  12. `update_time` datetime DEFAULT NULL,
  13. PRIMARY KEY (`id`),
  14. KEY `order_no_index` (`order_no`) USING BTREE,
  15. KEY `order_no_user_id_index` (`user_id`,`order_no`) USING BTREE
  16. ) ENGINE=InnoDB AUTO_INCREMENT=135 DEFAULT CHARSET=utf8;

create_time 数据创建时间
update_time 数据更新时间

配置pom.xml

  1. <build>
  2. <finalName>mmall</finalName>
  3. <plugins>
  4. <plugin>
  5. <groupId>org.mybatis.generator</groupId>
  6. <artifactId>mybatis-generator-maven-plugin</artifactId>
  7. <version>1.3.2</version>
  8. <configuration>
  9. <verbose>true</verbose>
  10. <overwrite>true</overwrite>
  11. </configuration>
  12. </plugin>
  13. </build>

datasource.properties

  1. db.driverLocation=/Users/imooc/mysql-connector-java-5.1.6-bin.jar
  2. db.driverClassName=com.mysql.jdbc.Driver
  3. #db.url=jdbc:mysql://192.1.1.1:3306/mmall?characterEncoding=utf-8
  4. db.url=jdbc:mysql://你的数据库IP:你的数据库Port/你的database?characterEncoding=utf-8
  5. db.username=mmall
  6. db.password=dbpassword
  7. db.initialSize = 20
  8. db.maxActive = 50
  9. db.maxIdle = 20
  10. db.minIdle = 10
  11. db.maxWait = 10
  12. db.defaultAutoCommit = true
  13. db.minEvictableIdleTimeMillis = 3600000

generatorConfig.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE generatorConfiguration
  3. PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  4. "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
  5. <generatorConfiguration>
  6. <!--导入属性配置-->
  7. <properties resource="datasource.properties"></properties>
  8. <!--指定特定数据库的jdbc驱动jar包的位置-->
  9. <classPathEntry location="${db.driverLocation}"/>
  10. <context id="default" targetRuntime="MyBatis3">
  11. <!-- optional,旨在创建class时,对注释进行控制 -->
  12. <commentGenerator>
  13. <property name="suppressDate" value="true"/>
  14. <property name="suppressAllComments" value="true"/>
  15. </commentGenerator>
  16. <!--jdbc的数据库连接 -->
  17. <jdbcConnection
  18. driverClass="${db.driverClassName}"
  19. connectionURL="${db.url}"
  20. userId="${db.username}"
  21. password="${db.password}">
  22. </jdbcConnection>
  23. <!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制-->
  24. <javaTypeResolver>
  25. <property name="forceBigDecimals" value="false"/>
  26. </javaTypeResolver>
  27. <!-- Model模型生成器,用来生成含有主键key的类,记录类 以及查询Example类
  28. targetPackage 指定生成的model生成所在的包名
  29. targetProject 指定在该项目下所在的路径
  30. -->
  31. <!--<javaModelGenerator targetPackage="com.mmall.pojo" targetProject=".\src\main\java">-->
  32. <javaModelGenerator targetPackage="com.mmall.pojo" targetProject="./src/main/java">
  33. <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
  34. <property name="enableSubPackages" value="false"/>
  35. <!-- 是否对model添加 构造函数 -->
  36. <property name="constructorBased" value="true"/>
  37. <!-- 是否对类CHAR类型的列的数据进行trim操作 -->
  38. <property name="trimStrings" value="true"/>
  39. <!-- 建立的Model对象是否 不可改变 即生成的Model对象不会有 setter方法,只有构造方法 -->
  40. <property name="immutable" value="false"/>
  41. </javaModelGenerator>
  42. <!--mapper映射文件生成所在的目录 为每一个数据库的表生成对应的SqlMap文件 -->
  43. <!--<sqlMapGenerator targetPackage="mappers" targetProject=".\src\main\resources">-->
  44. <sqlMapGenerator targetPackage="mappers" targetProject="./src/main/resources">
  45. <property name="enableSubPackages" value="false"/>
  46. </sqlMapGenerator>
  47. <!-- 客户端代码,生成易于使用的针对Model对象和XML配置文件 的代码
  48. type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象
  49. type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象
  50. type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口
  51. -->
  52. <!-- targetPackage:mapper接口dao生成的位置 -->
  53. <!--<javaClientGenerator type="XMLMAPPER" targetPackage="com.mmall.dao" targetProject=".\src\main\java">-->
  54. <javaClientGenerator type="XMLMAPPER" targetPackage="com.mmall.dao" targetProject="./src/main/java">
  55. <!-- enableSubPackages:是否让schema作为包的后缀 -->
  56. <property name="enableSubPackages" value="false" />
  57. </javaClientGenerator>
  58. <table tableName="mmall_shipping" domainObjectName="Shipping" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
  59. <table tableName="mmall_cart" domainObjectName="Cart" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
  60. <table tableName="mmall_cart_item" domainObjectName="CartItem" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
  61. <table tableName="mmall_category" domainObjectName="Category" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
  62. <table tableName="mmall_order" domainObjectName="Order" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
  63. <table tableName="mmall_order_item" domainObjectName="OrderItem" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
  64. <table tableName="mmall_pay_info" domainObjectName="PayInfo" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
  65. <table tableName="mmall_product" domainObjectName="Product" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
  66. <columnOverride column="detail" jdbcType="VARCHAR" />
  67. <columnOverride column="sub_images" jdbcType="VARCHAR" />
  68. </table>
  69. <table tableName="mmall_user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
  70. <!-- geelynote mybatis插件的搭建 -->
  71. </context>
  72. </generatorConfiguration>

运行

下载

配置pom.xml

  1. <!-- mybatis pager -->
  2. <dependency>
  3. <groupId>com.github.pagehelper</groupId>
  4. <artifactId>pagehelper</artifactId>
  5. <version>4.1.0</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>com.github.miemiedev</groupId>
  9. <artifactId>mybatis-paginator</artifactId>
  10. <version>1.2.17</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>com.github.jsqlparser</groupId>
  14. <artifactId>jsqlparser</artifactId>
  15. <version>0.9.4</version>
  16. </dependency>

方式一:配置web.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns="http://java.sun.com/xml/ns/javaee"
  4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  5. id="WebApp_ID" version="2.5">
  6. <welcome-file-list>
  7. <welcome-file>login.jsp</welcome-file>
  8. </welcome-file-list>
  9. <!-- 启动我们自己的listener -->
  10. <listener>
  11. <listener-class>com.atguigu.scw.manager.listener.MyAppListener</listener-class>
  12. </listener>
  13. <!-- 启动spring容器 -->
  14. <!-- needed for ContextLoaderListener -->
  15. <context-param>
  16. <param-name>contextConfigLocation</param-name>
  17. <param-value>classpath:spring-*.xml</param-value>
  18. </context-param>
  19. <!-- Bootstraps the root web application context before servlet initialization -->
  20. <listener>
  21. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  22. </listener>
  23. <!-- The front controller of this Spring Web application, responsible for
  24. handling all application requests -->
  25. <servlet>
  26. <servlet-name>springDispatcherServlet</servlet-name>
  27. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  28. <init-param>
  29. <param-name>contextConfigLocation</param-name>
  30. <param-value>classpath:springmvc.xml</param-value>
  31. </init-param>
  32. <load-on-startup>1</load-on-startup>
  33. </servlet>
  34. <!-- Map all requests to the DispatcherServlet for handling -->
  35. <servlet-mapping>
  36. <servlet-name>springDispatcherServlet</servlet-name>
  37. <url-pattern>/</url-pattern>
  38. </servlet-mapping>
  39. <!-- 加上字符编码过滤器 -->
  40. <filter>
  41. <filter-name>CharacterEncodingFilter</filter-name>
  42. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  43. <!-- 只是指定了编码格式 -->
  44. <init-param>
  45. <param-name>encoding</param-name>
  46. <param-value>utf-8</param-value>
  47. </init-param>
  48. <!-- 进行请求乱码解决 -->
  49. <init-param>
  50. <param-name>forceRequestEncoding</param-name>
  51. <param-value>true</param-value>
  52. </init-param>
  53. <init-param>
  54. <param-name>forceResponseEncoding</param-name>
  55. <param-value>true</param-value>
  56. </init-param>
  57. </filter>
  58. <filter-mapping>
  59. <filter-name>CharacterEncodingFilter</filter-name>
  60. <url-pattern>/*</url-pattern>
  61. </filter-mapping>
  62. </web-app>

方式二:配置web.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns="http://java.sun.com/xml/ns/javaee"
  4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  5. id="WebApp_ID" version="2.5">
  6. <display-name>Archetype Created Web Application</display-name>
  7. <filter>
  8. <filter-name>characterEncodingFilter</filter-name>
  9. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  10. <init-param>
  11. <param-name>encoding</param-name>
  12. <param-value>UTF-8</param-value>
  13. </init-param>
  14. <init-param>
  15. <param-name>forceEncoding</param-name>
  16. <param-value>true</param-value>
  17. </init-param>
  18. </filter>
  19. <filter-mapping>
  20. <filter-name>characterEncodingFilter</filter-name>
  21. <url-pattern>/*</url-pattern>
  22. </filter-mapping>
  23. <listener>
  24. <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  25. </listener>
  26. <listener>
  27. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  28. </listener>
  29. <context-param>
  30. <param-name>contextConfigLocation</param-name>
  31. <param-value>
  32. classpath:applicationContext.xml
  33. </param-value>
  34. </context-param>
  35. <servlet>
  36. <servlet-name>dispatcher</servlet-name>
  37. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  38. <load-on-startup>1</load-on-startup>
  39. </servlet>
  40. <servlet-mapping>
  41. <servlet-name>dispatcher</servlet-name>
  42. <url-pattern>*.do</url-pattern>
  43. </servlet-mapping>
  44. </web-app>

FeHelper

Restlet Client

入参需要指定当前用户id

盐值加密

MD5Util.java

  1. package com.mmall.util;
  2. import org.springframework.util.StringUtils;
  3. import java.security.MessageDigest;
  4. /**
  5. * Created by geely
  6. */
  7. public class MD5Util {
  8. private static String byteArrayToHexString(byte b[]) {
  9. StringBuffer resultSb = new StringBuffer();
  10. for (int i = 0; i < b.length; i++)
  11. resultSb.append(byteToHexString(b[i]));
  12. return resultSb.toString();
  13. }
  14. private static String byteToHexString(byte b) {
  15. int n = b;
  16. if (n < 0)
  17. n += 256;
  18. int d1 = n / 16;
  19. int d2 = n % 16;
  20. return hexDigits[d1] + hexDigits[d2];
  21. }
  22. /**
  23. * 返回大写MD5
  24. *
  25. * @param origin
  26. * @param charsetname
  27. * @return
  28. */
  29. private static String MD5Encode(String origin, String charsetname) {
  30. String resultString = null;
  31. try {
  32. resultString = new String(origin);
  33. MessageDigest md = MessageDigest.getInstance("MD5");
  34. if (charsetname == null || "".equals(charsetname))
  35. resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
  36. else
  37. resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
  38. } catch (Exception exception) {
  39. }
  40. return resultString.toUpperCase();
  41. }
  42. public static String MD5EncodeUtf8(String origin) {
  43. origin = origin + PropertiesUtil.getProperty("password.salt", "");
  44. return MD5Encode(origin, "utf-8");
  45. }
  46. private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
  47. "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
  48. }

PropertiesUtil.java

读取src/main/resources目录下的配置文件

  1. package com.mmall.util;
  2. import org.apache.commons.lang3.StringUtils;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import java.io.IOException;
  6. import java.io.InputStreamReader;
  7. import java.util.Properties;
  8. /**
  9. * Created by geely
  10. */
  11. public class PropertiesUtil {
  12. private static Logger logger = LoggerFactory.getLogger(PropertiesUtil.class);
  13. private static Properties props;
  14. static {
  15. String fileName = "mmall.properties";
  16. props = new Properties();
  17. try {
  18. props.load(new InputStreamReader(PropertiesUtil.class.getClassLoader().getResourceAsStream(fileName),"UTF-8"));
  19. } catch (IOException e) {
  20. logger.error("配置文件读取异常",e);
  21. }
  22. }
  23. public static String getProperty(String key){
  24. String value = props.getProperty(key.trim());
  25. if(StringUtils.isBlank(value)){
  26. return null;
  27. }
  28. return value.trim();
  29. }
  30. public static String getProperty(String key,String defaultValue){
  31. String value = props.getProperty(key.trim());
  32. if(StringUtils.isBlank(value)){
  33. value = defaultValue;
  34. }
  35. return value.trim();
  36. }
  37. }

mmall.properties

  1. ftp.server.ip=你的FTP服务器ip地址
  2. ftp.user=mmallftp
  3. ftp.pass=ftppassword
  4. ftp.server.http.prefix=http://img.happymmall.com/
  5. alipay.callback.url=http://www.happymmall.com/order/alipay_callback.do
  6. password.salt = geelysdafaqj23ou89ZXcj@#$@#$#@KJdjklj;D../dSF.,

应用:明文加密

设置token并传给前台用户

设置token并传给前台用户

验证token

TokenCache.java

  1. package com.mmall.common;
  2. import com.google.common.cache.CacheBuilder;
  3. import com.google.common.cache.CacheLoader;
  4. import com.google.common.cache.LoadingCache;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import java.util.concurrent.TimeUnit;
  8. /**
  9. * Created by geely
  10. */
  11. public class TokenCache {
  12. private static Logger logger = LoggerFactory.getLogger(TokenCache.class);
  13. public static final String TOKEN_PREFIX = "token_";
  14. //LRU算法
  15. private static LoadingCache<String,String> localCache = CacheBuilder.newBuilder().initialCapacity(1000).maximumSize(10000).expireAfterAccess(12, TimeUnit.HOURS)
  16. .build(new CacheLoader<String, String>() {
  17. //默认的数据加载实现,当调用get取值的时候,如果key没有对应的值,就调用这个方法进行加载.
  18. @Override
  19. public String load(String s) throws Exception {
  20. return "null";
  21. }
  22. });
  23. public static void setKey(String key,String value){
  24. localCache.put(key,value);
  25. }
  26. public static String getKey(String key){
  27. String value = null;
  28. try {
  29. value = localCache.get(key);
  30. if("null".equals(value)){
  31. return null;
  32. }
  33. return value;
  34. }catch (Exception e){
  35. logger.error("localCache get error",e);
  36. }
  37. return null;
  38. }
  39. }

UserServiceImpl.java

  1. public ServerResponse<String> checkAnswer(String username,String question,String answer){
  2. int resultCount = userMapper.checkAnswer(username,question,answer);
  3. if(resultCount>0){
  4. //说明问题及问题答案是这个用户的,并且是正确的
  5. String forgetToken = UUID.randomUUID().toString();
  6. TokenCache.setKey(TokenCache.TOKEN_PREFIX+username,forgetToken);
  7. return ServerResponse.createBySuccess(forgetToken);
  8. }
  9. return ServerResponse.createByErrorMessage("问题的答案错误");
  10. }
  11. public ServerResponse<String> forgetResetPassword(String username,String passwordNew,String forgetToken){
  12. if(org.apache.commons.lang3.StringUtils.isBlank(forgetToken)){
  13. return ServerResponse.createByErrorMessage("参数错误,token需要传递");
  14. }
  15. ServerResponse validResponse = this.checkValid(username,Const.USERNAME);
  16. if(validResponse.isSuccess()){
  17. //用户不存在
  18. return ServerResponse.createByErrorMessage("用户不存在");
  19. }
  20. String token = TokenCache.getKey(TokenCache.TOKEN_PREFIX+username);
  21. if(org.apache.commons.lang3.StringUtils.isBlank(token)){
  22. return ServerResponse.createByErrorMessage("token无效或者过期");
  23. }
  24. if(org.apache.commons.lang3.StringUtils.equals(forgetToken,token)){
  25. String md5Password = MD5Util.MD5EncodeUtf8(passwordNew);
  26. int rowCount = userMapper.updatePasswordByUsername(username,md5Password);
  27. if(rowCount > 0){
  28. return ServerResponse.createBySuccessMessage("修改密码成功");
  29. }
  30. }else{
  31. return ServerResponse.createByErrorMessage("token错误,请重新获取重置密码的token");
  32. }
  33. return ServerResponse.createByErrorMessage("修改密码失败");
  34. }

ServerResponse.java

  1. package com.mmall.common;
  2. import org.codehaus.jackson.annotate.JsonIgnore;
  3. import org.codehaus.jackson.map.annotate.JsonSerialize;
  4. import java.io.Serializable;
  5. /**
  6. * Created by geely
  7. */
  8. @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
  9. //保证序列化json的时候,如果是null的对象,key也会消失
  10. public class ServerResponse<T> implements Serializable {
  11. private int status;
  12. private String msg;
  13. private T data;
  14. private ServerResponse(int status){
  15. this.status = status;
  16. }
  17. private ServerResponse(int status,T data){
  18. this.status = status;
  19. this.data = data;
  20. }
  21. private ServerResponse(int status,String msg,T data){
  22. this.status = status;
  23. this.msg = msg;
  24. this.data = data;
  25. }
  26. private ServerResponse(int status,String msg){
  27. this.status = status;
  28. this.msg = msg;
  29. }
  30. @JsonIgnore
  31. //使之不在json序列化结果当中
  32. public boolean isSuccess(){
  33. return this.status == ResponseCode.SUCCESS.getCode();
  34. }
  35. public int getStatus(){
  36. return status;
  37. }
  38. public T getData(){
  39. return data;
  40. }
  41. public String getMsg(){
  42. return msg;
  43. }
  44. public static <T> ServerResponse<T> createBySuccess(){
  45. return new ServerResponse<T>(ResponseCode.SUCCESS.getCode());
  46. }
  47. public static <T> ServerResponse<T> createBySuccessMessage(String msg){
  48. return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(),msg);
  49. }
  50. public static <T> ServerResponse<T> createBySuccess(T data){
  51. return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(),data);
  52. }
  53. public static <T> ServerResponse<T> createBySuccess(String msg,T data){
  54. return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(),msg,data);
  55. }
  56. public static <T> ServerResponse<T> createByError(){
  57. return new ServerResponse<T>(ResponseCode.ERROR.getCode(),ResponseCode.ERROR.getDesc());
  58. }
  59. public static <T> ServerResponse<T> createByErrorMessage(String errorMessage){
  60. return new ServerResponse<T>(ResponseCode.ERROR.getCode(),errorMessage);
  61. }
  62. public static <T> ServerResponse<T> createByErrorCodeMessage(int errorCode,String errorMessage){
  63. return new ServerResponse<T>(errorCode,errorMessage);
  64. }
  65. }

ResponseCode.java

  1. package com.mmall.common;
  2. /**
  3. * Created by geely
  4. */
  5. public enum ResponseCode {
  6. SUCCESS(0,"SUCCESS"),
  7. ERROR(1,"ERROR"),
  8. NEED_LOGIN(10,"NEED_LOGIN"),
  9. ILLEGAL_ARGUMENT(2,"ILLEGAL_ARGUMENT");
  10. private final int code;
  11. private final String desc;
  12. ResponseCode(int code,String desc){
  13. this.code = code;
  14. this.desc = desc;
  15. }
  16. public int getCode(){
  17. return code;
  18. }
  19. public String getDesc(){
  20. return desc;
  21. }
  22. }
  1. /**
  2. * 递归查询本节点的id及孩子节点的id
  3. * @param categoryId
  4. * @return
  5. */
  6. public ServerResponse<List<Integer>> selectCategoryAndChildrenById(Integer categoryId){
  7. Set<Category> categorySet = Sets.newHashSet();
  8. findChildCategory(categorySet,categoryId);
  9. List<Integer> categoryIdList = Lists.newArrayList();
  10. if(categoryId != null){
  11. for(Category categoryItem : categorySet){
  12. categoryIdList.add(categoryItem.getId());
  13. }
  14. }
  15. return ServerResponse.createBySuccess(categoryIdList);
  16. }
  17. //递归算法,算出子节点
  18. private Set<Category> findChildCategory(Set<Category> categorySet ,Integer categoryId){
  19. Category category = categoryMapper.selectByPrimaryKey(categoryId);
  20. if(category != null){
  21. categorySet.add(category);
  22. }
  23. //查找子节点,递归算法一定要有一个退出的条件
  24. List<Category> categoryList = categoryMapper.selectCategoryChildrenByParentId(categoryId);
  25. for(Category categoryItem : categoryList){
  26. findChildCategory(categorySet,categoryItem.getId());
  27. }
  28. return categorySet;
  29. }

Set集合

重写自定义对象Category的equalshashCode方法

Product.java

  1. package com.mmall.pojo;
  2. import java.math.BigDecimal;
  3. import java.util.Date;
  4. public class Product {
  5. private Integer id;
  6. private Integer categoryId;
  7. private String name;
  8. private String subtitle;
  9. private String mainImage;
  10. private String subImages;
  11. private String detail;
  12. private BigDecimal price;
  13. private Integer stock;
  14. private Integer status;
  15. private Date createTime;
  16. private Date updateTime;
  17. public Product(Integer id, Integer categoryId, String name, String subtitle, String mainImage, String subImages, String detail, BigDecimal price, Integer stock, Integer status, Date createTime, Date updateTime) {
  18. this.id = id;
  19. this.categoryId = categoryId;
  20. this.name = name;
  21. this.subtitle = subtitle;
  22. this.mainImage = mainImage;
  23. this.subImages = subImages;
  24. this.detail = detail;
  25. this.price = price;
  26. this.stock = stock;
  27. this.status = status;
  28. this.createTime = createTime;
  29. this.updateTime = updateTime;
  30. }
  31. public Product() {
  32. super();
  33. }
  34. public Integer getId() {
  35. return id;
  36. }
  37. public void setId(Integer id) {
  38. this.id = id;
  39. }
  40. public Integer getCategoryId() {
  41. return categoryId;
  42. }
  43. public void setCategoryId(Integer categoryId) {
  44. this.categoryId = categoryId;
  45. }
  46. public String getName() {
  47. return name;
  48. }
  49. public void setName(String name) {
  50. this.name = name == null ? null : name.trim();
  51. }
  52. public String getSubtitle() {
  53. return subtitle;
  54. }
  55. public void setSubtitle(String subtitle) {
  56. this.subtitle = subtitle == null ? null : subtitle.trim();
  57. }
  58. public String getMainImage() {
  59. return mainImage;
  60. }
  61. public void setMainImage(String mainImage) {
  62. this.mainImage = mainImage == null ? null : mainImage.trim();
  63. }
  64. public String getSubImages() {
  65. return subImages;
  66. }
  67. public void setSubImages(String subImages) {
  68. this.subImages = subImages == null ? null : subImages.trim();
  69. }
  70. public String getDetail() {
  71. return detail;
  72. }
  73. public void setDetail(String detail) {
  74. this.detail = detail == null ? null : detail.trim();
  75. }
  76. public BigDecimal getPrice() {
  77. return price;
  78. }
  79. public void setPrice(BigDecimal price) {
  80. this.price = price;
  81. }
  82. public Integer getStock() {
  83. return stock;
  84. }
  85. public void setStock(Integer stock) {
  86. this.stock = stock;
  87. }
  88. public Integer getStatus() {
  89. return status;
  90. }
  91. public void setStatus(Integer status) {
  92. this.status = status;
  93. }
  94. public Date getCreateTime() {
  95. return createTime;
  96. }
  97. public void setCreateTime(Date createTime) {
  98. this.createTime = createTime;
  99. }
  100. public Date getUpdateTime() {
  101. return updateTime;
  102. }
  103. public void setUpdateTime(Date updateTime) {
  104. this.updateTime = updateTime;
  105. }
  106. }

ProductDetailVo.java

  1. package com.mmall.vo;
  2. import java.math.BigDecimal;
  3. /**
  4. * Created by geely
  5. */
  6. public class ProductDetailVo {
  7. private Integer id;
  8. private Integer categoryId;
  9. private String name;
  10. private String subtitle;
  11. private String mainImage;
  12. private String subImages;
  13. private String detail;
  14. private BigDecimal price;
  15. private Integer stock;
  16. private Integer status;
  17. private String createTime;
  18. private String updateTime;
  19. private String imageHost;
  20. private Integer parentCategoryId;
  21. public Integer getId() {
  22. return id;
  23. }
  24. public void setId(Integer id) {
  25. this.id = id;
  26. }
  27. public Integer getCategoryId() {
  28. return categoryId;
  29. }
  30. public void setCategoryId(Integer categoryId) {
  31. this.categoryId = categoryId;
  32. }
  33. public String getName() {
  34. return name;
  35. }
  36. public void setName(String name) {
  37. this.name = name;
  38. }
  39. public String getSubtitle() {
  40. return subtitle;
  41. }
  42. public void setSubtitle(String subtitle) {
  43. this.subtitle = subtitle;
  44. }
  45. public String getMainImage() {
  46. return mainImage;
  47. }
  48. public void setMainImage(String mainImage) {
  49. this.mainImage = mainImage;
  50. }
  51. public String getSubImages() {
  52. return subImages;
  53. }
  54. public void setSubImages(String subImages) {
  55. this.subImages = subImages;
  56. }
  57. public String getDetail() {
  58. return detail;
  59. }
  60. public void setDetail(String detail) {
  61. this.detail = detail;
  62. }
  63. public BigDecimal getPrice() {
  64. return price;
  65. }
  66. public void setPrice(BigDecimal price) {
  67. this.price = price;
  68. }
  69. public Integer getStock() {
  70. return stock;
  71. }
  72. public void setStock(Integer stock) {
  73. this.stock = stock;
  74. }
  75. public Integer getStatus() {
  76. return status;
  77. }
  78. public void setStatus(Integer status) {
  79. this.status = status;
  80. }
  81. public String getCreateTime() {
  82. return createTime;
  83. }
  84. public void setCreateTime(String createTime) {
  85. this.createTime = createTime;
  86. }
  87. public String getUpdateTime() {
  88. return updateTime;
  89. }
  90. public void setUpdateTime(String updateTime) {
  91. this.updateTime = updateTime;
  92. }
  93. public String getImageHost() {
  94. return imageHost;
  95. }
  96. public void setImageHost(String imageHost) {
  97. this.imageHost = imageHost;
  98. }
  99. public Integer getParentCategoryId() {
  100. return parentCategoryId;
  101. }
  102. public void setParentCategoryId(Integer parentCategoryId) {
  103. this.parentCategoryId = parentCategoryId;
  104. }
  105. }

Tomcat启动加载静态代码块

  1. package com.mmall.util;
  2. import org.apache.commons.lang3.StringUtils;
  3. import org.joda.time.DateTime;
  4. import org.joda.time.format.DateTimeFormat;
  5. import org.joda.time.format.DateTimeFormatter;
  6. import java.util.Date;
  7. /**
  8. * Created by geely
  9. */
  10. public class DateTimeUtil {
  11. //joda-time
  12. //str->Date
  13. //Date->str
  14. public static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss";
  15. public static Date strToDate(String dateTimeStr,String formatStr){
  16. DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(formatStr);
  17. DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr);
  18. return dateTime.toDate();
  19. }
  20. public static String dateToStr(Date date,String formatStr){
  21. if(date == null){
  22. return StringUtils.EMPTY;
  23. }
  24. DateTime dateTime = new DateTime(date);
  25. return dateTime.toString(formatStr);
  26. }
  27. public static Date strToDate(String dateTimeStr){
  28. DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(STANDARD_FORMAT);
  29. DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr);
  30. return dateTime.toDate();
  31. }
  32. public static String dateToStr(Date date){
  33. if(date == null){
  34. return StringUtils.EMPTY;
  35. }
  36. DateTime dateTime = new DateTime(date);
  37. return dateTime.toString(STANDARD_FORMAT);
  38. }
  39. public static void main(String[] args) {
  40. System.out.println(DateTimeUtil.dateToStr(new Date(),"yyyy-MM-dd HH:mm:ss"));
  41. System.out.println(DateTimeUtil.strToDate("2010-01-01 11:11:11","yyyy-MM-dd HH:mm:ss"));
  42. }
  43. }

配置pom.xml

实现

先将文件上传到本地==>上传到远程ftp>删除本地文件

配置pom.xml

  1. <!-- file upload -->
  2. <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
  3. <dependency>
  4. <groupId>commons-fileupload</groupId>
  5. <artifactId>commons-fileupload</artifactId>
  6. <version>1.2.2</version>
  7. </dependency>
  8. <dependency>
  9. <groupId>commons-io</groupId>
  10. <artifactId>commons-io</artifactId>
  11. <version>2.0.1</version>
  12. </dependency>

配置dispatcher-servlet.xml

  1. <!-- 文件上传 -->
  2. <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
  3. <property name="maxUploadSize" value="10485760"/> <!-- 10m -->
  4. <property name="maxInMemorySize" value="4096" />
  5. <property name="defaultEncoding" value="UTF-8"></property>
  6. </bean>

FileServiceImpl.java

  1. package com.mmall.service.impl;
  2. import com.google.common.collect.Lists;
  3. import com.mmall.service.IFileService;
  4. import com.mmall.util.FTPUtil;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.stereotype.Service;
  8. import org.springframework.web.multipart.MultipartFile;
  9. import java.io.File;
  10. import java.io.IOException;
  11. import java.util.UUID;
  12. /**
  13. * Created by geely
  14. */
  15. @Service("iFileService")
  16. public class FileServiceImpl implements IFileService {
  17. private Logger logger = LoggerFactory.getLogger(FileServiceImpl.class);
  18. public String upload(MultipartFile file,String path){
  19. String fileName = file.getOriginalFilename();
  20. //扩展名
  21. //abc.jpg
  22. String fileExtensionName = fileName.substring(fileName.lastIndexOf(".")+1);
  23. String uploadFileName = UUID.randomUUID().toString()+"."+fileExtensionName;
  24. logger.info("开始上传文件,上传文件的文件名:{},上传的路径:{},新文件名:{}",fileName,path,uploadFileName);
  25. File fileDir = new File(path);
  26. if(!fileDir.exists()){
  27. fileDir.setWritable(true);
  28. fileDir.mkdirs();
  29. }
  30. File targetFile = new File(path,uploadFileName);
  31. try {
  32. file.transferTo(targetFile);
  33. //文件已经上传成功了
  34. FTPUtil.uploadFile(Lists.newArrayList(targetFile));
  35. //已经上传到ftp服务器上
  36. targetFile.delete();
  37. } catch (IOException e) {
  38. logger.error("上传文件异常",e);
  39. return null;
  40. }
  41. //A:abc.jpg
  42. //B:abc.jpg
  43. return targetFile.getName();
  44. }
  45. }

连接远程ftp,上传文件

FTPUtil.java

  1. package com.mmall.util;
  2. import org.apache.commons.net.ftp.FTPClient;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import java.io.File;
  6. import java.io.FileInputStream;
  7. import java.io.IOException;
  8. import java.util.List;
  9. /**
  10. * Created by geely
  11. */
  12. public class FTPUtil {
  13. private static final Logger logger = LoggerFactory.getLogger(FTPUtil.class);
  14. private static String ftpIp = PropertiesUtil.getProperty("ftp.server.ip");
  15. private static String ftpUser = PropertiesUtil.getProperty("ftp.user");
  16. private static String ftpPass = PropertiesUtil.getProperty("ftp.pass");
  17. public FTPUtil(String ip,int port,String user,String pwd){
  18. this.ip = ip;
  19. this.port = port;
  20. this.user = user;
  21. this.pwd = pwd;
  22. }
  23. public static boolean uploadFile(List<File> fileList) throws IOException {
  24. FTPUtil ftpUtil = new FTPUtil(ftpIp,21,ftpUser,ftpPass);
  25. logger.info("开始连接ftp服务器");
  26. boolean result = ftpUtil.uploadFile("img",fileList);
  27. logger.info("开始连接ftp服务器,结束上传,上传结果:{}");
  28. return result;
  29. }
  30. private boolean uploadFile(String remotePath,List<File> fileList) throws IOException {
  31. boolean uploaded = true;
  32. FileInputStream fis = null;
  33. //连接FTP服务器
  34. if(connectServer(this.ip,this.port,this.user,this.pwd)){
  35. try {
  36. ftpClient.changeWorkingDirectory(remotePath);
  37. ftpClient.setBufferSize(1024);
  38. ftpClient.setControlEncoding("UTF-8");
  39. ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
  40. ftpClient.enterLocalPassiveMode();
  41. for(File fileItem : fileList){
  42. fis = new FileInputStream(fileItem);
  43. ftpClient.storeFile(fileItem.getName(),fis);
  44. }
  45. } catch (IOException e) {
  46. logger.error("上传文件异常",e);
  47. uploaded = false;
  48. e.printStackTrace();
  49. } finally {
  50. fis.close();
  51. ftpClient.disconnect();
  52. }
  53. }
  54. return uploaded;
  55. }
  56. private boolean connectServer(String ip,int port,String user,String pwd){
  57. boolean isSuccess = false;
  58. ftpClient = new FTPClient();
  59. try {
  60. ftpClient.connect(ip);
  61. isSuccess = ftpClient.login(user,pwd);
  62. } catch (IOException e) {
  63. logger.error("连接FTP服务器异常",e);
  64. }
  65. return isSuccess;
  66. }
  67. private String ip;
  68. private int port;
  69. private String user;
  70. private String pwd;
  71. private FTPClient ftpClient;
  72. public String getIp() {
  73. return ip;
  74. }
  75. public void setIp(String ip) {
  76. this.ip = ip;
  77. }
  78. public int getPort() {
  79. return port;
  80. }
  81. public void setPort(int port) {
  82. this.port = port;
  83. }
  84. public String getUser() {
  85. return user;
  86. }
  87. public void setUser(String user) {
  88. this.user = user;
  89. }
  90. public String getPwd() {
  91. return pwd;
  92. }
  93. public void setPwd(String pwd) {
  94. this.pwd = pwd;
  95. }
  96. public FTPClient getFtpClient() {
  97. return ftpClient;
  98. }
  99. public void setFtpClient(FTPClient ftpClient) {
  100. this.ftpClient = ftpClient;
  101. }
  102. }

和ftp文件上传类似,只是对返回值有特殊要求

  1. package com.mmall.util;
  2. import java.math.BigDecimal;
  3. /**
  4. * Created by geely
  5. */
  6. public class BigDecimalUtil {
  7. private BigDecimalUtil(){
  8. }
  9. public static BigDecimal add(double v1,double v2){
  10. BigDecimal b1 = new BigDecimal(Double.toString(v1));
  11. BigDecimal b2 = new BigDecimal(Double.toString(v2));
  12. return b1.add(b2);
  13. }
  14. public static BigDecimal sub(double v1,double v2){
  15. BigDecimal b1 = new BigDecimal(Double.toString(v1));
  16. BigDecimal b2 = new BigDecimal(Double.toString(v2));
  17. return b1.subtract(b2);
  18. }
  19. public static BigDecimal mul(double v1,double v2){
  20. BigDecimal b1 = new BigDecimal(Double.toString(v1));
  21. BigDecimal b2 = new BigDecimal(Double.toString(v2));
  22. return b1.multiply(b2);
  23. }
  24. public static BigDecimal div(double v1,double v2){
  25. BigDecimal b1 = new BigDecimal(Double.toString(v1));
  26. BigDecimal b2 = new BigDecimal(Double.toString(v2));
  27. return b1.divide(b2,2,BigDecimal.ROUND_HALF_UP);//四舍五入,保留2位小数
  28. //除不尽的情况
  29. }
  30. }

一定要用BigDecimalString构造函数

  1. public class BigDecimalTest {
  2. @Test
  3. public void test1(){
  4. System.out.println(0.05+0.01);
  5. System.out.println(1.0-0.42);
  6. System.out.println(4.015*100);
  7. System.out.println(123.3/100);
  8. }
  9. @Test
  10. public void test2(){
  11. BigDecimal b1 = new BigDecimal(0.05);
  12. BigDecimal b2 = new BigDecimal(0.01);
  13. System.out.println(b1.add(b2));
  14. }
  15. @Test
  16. public void test3(){
  17. BigDecimal b1 = new BigDecimal("0.05");
  18. BigDecimal b2 = new BigDecimal("0.01");
  19. System.out.println(b1.add(b2));
  20. }
  21. }

Const.java

  1. package com.mmall.common;
  2. import com.google.common.collect.Sets;
  3. import java.util.Set;
  4. /**
  5. * Created by geely
  6. */
  7. public class Const {
  8. public static final String CURRENT_USER = "currentUser";
  9. public static final String EMAIL = "email";
  10. public static final String USERNAME = "username";
  11. public interface ProductListOrderBy{
  12. Set<String> PRICE_ASC_DESC = Sets.newHashSet("price_desc","price_asc");
  13. }
  14. public interface Cart{
  15. int CHECKED = 1;//即购物车选中状态
  16. int UN_CHECKED = 0;//购物车中未选中状态
  17. String LIMIT_NUM_FAIL = "LIMIT_NUM_FAIL";
  18. String LIMIT_NUM_SUCCESS = "LIMIT_NUM_SUCCESS";
  19. }
  20. public interface Role{
  21. int ROLE_CUSTOMER = 0; //普通用户
  22. int ROLE_ADMIN = 1;//管理员
  23. }
  24. public enum ProductStatusEnum{
  25. ON_SALE(1,"在线");
  26. private String value;
  27. private int code;
  28. ProductStatusEnum(int code,String value){
  29. this.code = code;
  30. this.value = value;
  31. }
  32. public String getValue() {
  33. return value;
  34. }
  35. public int getCode() {
  36. return code;
  37. }
  38. }
  39. public enum OrderStatusEnum{
  40. CANCELED(0,"已取消"),
  41. NO_PAY(10,"未支付"),
  42. PAID(20,"已付款"),
  43. SHIPPED(40,"已发货"),
  44. ORDER_SUCCESS(50,"订单完成"),
  45. ORDER_CLOSE(60,"订单关闭");
  46. OrderStatusEnum(int code,String value){
  47. this.code = code;
  48. this.value = value;
  49. }
  50. private String value;
  51. private int code;
  52. public String getValue() {
  53. return value;
  54. }
  55. public int getCode() {
  56. return code;
  57. }
  58. public static OrderStatusEnum codeOf(int code){
  59. for(OrderStatusEnum orderStatusEnum : values()){
  60. if(orderStatusEnum.getCode() == code){
  61. return orderStatusEnum;
  62. }
  63. }
  64. throw new RuntimeException("么有找到对应的枚举");
  65. }
  66. }
  67. public interface AlipayCallback{
  68. String TRADE_STATUS_WAIT_BUYER_PAY = "WAIT_BUYER_PAY";
  69. String TRADE_STATUS_TRADE_SUCCESS = "TRADE_SUCCESS";
  70. String RESPONSE_SUCCESS = "success";
  71. String RESPONSE_FAILED = "failed";
  72. }
  73. public enum PayPlatformEnum{
  74. ALIPAY(1,"支付宝");
  75. PayPlatformEnum(int code,String value){
  76. this.code = code;
  77. this.value = value;
  78. }
  79. private String value;
  80. private int code;
  81. public String getValue() {
  82. return value;
  83. }
  84. public int getCode() {
  85. return code;
  86. }
  87. }
  88. public enum PaymentTypeEnum{
  89. ONLINE_PAY(1,"在线支付");
  90. PaymentTypeEnum(int code,String value){
  91. this.code = code;
  92. this.value = value;
  93. }
  94. private String value;
  95. private int code;
  96. public String getValue() {
  97. return value;
  98. }
  99. public int getCode() {
  100. return code;
  101. }
  102. public static PaymentTypeEnum codeOf(int code){
  103. for(PaymentTypeEnum paymentTypeEnum : values()){
  104. if(paymentTypeEnum.getCode() == code){
  105. return paymentTypeEnum;
  106. }
  107. }
  108. throw new RuntimeException("么有找到对应的枚举");
  109. }
  110. }
  111. }

使用


收货地址对象必须要有getset方法

当面付

当面付Demo

服务端SDK下载和使用教程

沙箱环境使用

生成RSA密钥

导入依赖

配置maven插件,除了pom.xml配置的依赖,lib包中的依赖也会一起打包部署

配置沙箱环境zfbinfo.properties

  1. # 支付宝网关名、partnerId和appId
  2. open_api_domain = https://openapi.alipaydev.com/gateway.do
  3. mcloud_api_domain = http://mcloudmonitor.com/gateway.do
  4. pid = 2088102180444972
  5. appid = 2016102100728313
  6. # RSA私钥、公钥和支付宝公钥
  7. private_key = MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCKQ2pEIzXM4IoN1cMzOFXdlk8yVX2cKXWITZ92EGAQQcRytaV07yQOaz3UE9KTeT9Nu628G+HZMsJUxQjEUETagmY5nLtbeL35M2UcibYpM3e2gVTtUW86CA65GCdLzUhdIug8yf2F9zWayzG4sHZ9DcTezG6ZjFu+EtDpFgg+CtqY7n/ihjTIqeE1lX0C2ZIKpIYs7QjR8AztB/qRcpOJKRfMKGDgmT9GALN8LeFEYCbQ+W/GJHN8bQ0Bk1Ll6EKQ4cHXZ1Yko+aXaRfbXfUZYgD9hwAVlxtwZndgeFX8KapOCw0J25pzV4WkutIjMlt7I2Q1jaWNoKLuxtz4M2mzAgMBAAECggEAAhnsL4TpeGehMXyiLtEYXPm/0mACPLFUm/GyDrVJAHY/ag7gqNpJjf6LPgHfHWamU6Qai9VQpWBkG62y6Gjf4wJAU3fSUR2QpYzmaHyfTBkAJMHqbIDkU9lzf9SiJEDGbMPvC512QOb05ZlY9Bmac2QWLdylgafkbQsUKbawAWFa/BAOMIp0tgYLW8/yY2aG6jeLqhOgTo8MWIW5d1qHtX5m/x7g97dYYMdX3kTo2i1dFLUVfEOvZe4US6VBvLg71dMxwadVF5YMaY9jq/ShPD0Gkf29wdThwsjcH6u9Tq/KArQTK+z02DAGkdWOcue3pHql+gvoIA8U5uFDdIeYwQKBgQDri3jPkDKi48efdKQk38rn+CJYeNFNRAhlly3h2AHaFEY92XRlBsho/vGFg43BvHu+cMz0Run4SS8Vo09vcTIY6p2xNMffjR0w2gQqx6PUdGHBFtw7FavxN4uVtVhL6uTAqfBv97mqQO0bq+DhOGwSRNIWqvnzfXywqwmXhKYECwKBgQCWRTl6tNv8scxPq4fpRL/uw71TU6XqSS/nME7KT4uyQPAXPk0mXVVwdmyST9Crlr6O6WJopPe9nMIFUYdjdkLfGKLCR96AH3U7frr4jf60eDYEhfHGIzln/ptrTJLvvbXTaPctAaZd6TIv63QVz3yim4MMl3VSdRlrE+O9R5ZR+QKBgQDjEP8TyUSnNsJX+4/JZFwsp04kz8OlorIdjVHT5/JREz5rnVfRlGpanXqjZSCg5Vy9R+ysiDhA+/wB9f87xXmv/2ypSeJspZLAZ0uhGffbdZ5PEASaiNfKn+tWFQ3bkcOX37tDlSJM+G4bQOR2+XdlXSbSZ1yx2AT+IsQKZvvL5QKBgQCPZEUiEz0sV1kX2R2a+XCQ3RVnUxWqh+X/HPjCUr+B/DdeZqPl7QAfjdGymBkN842o/4lZQ7nnpJL70j14KpxLGM4Ox9fIuLv8ZsTxc0XOXjtle48nO+uGkc0qyWoY/RVpQ+tBdiaTzHeIhIxEV7adz/lwZYKdiYIUzGjv8ES/uQKBgCgeWysXjahCQItxx5fTrS8SQFP7Dx5vDW+UkqQ2pbL0AlHyUS7pWJj3AAe3pn4AJZZp4SZPoQP+Z8JPqDA6MrQWHYMi0XkMuMYwLWbGCkmf1MnjUxgOaLXoItjxS/y3jQfeOmHhmOAVkjnEvAh+BWlZxFMv2kiuHRU72bNa0rDI
  8. public_key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAikNqRCM1zOCKDdXDMzhV3ZZPMlV9nCl1iE2fdhBgEEHEcrWldO8kDms91BPSk3k/TbutvBvh2TLCVMUIxFBE2oJmOZy7W3i9+TNlHIm2KTN3toFU7VFvOggOuRgnS81IXSLoPMn9hfc1mssxuLB2fQ3E3sxumYxbvhLQ6RYIPgramO5/4oY0yKnhNZV9AtmSCqSGLO0I0fAM7Qf6kXKTiSkXzChg4Jk/RgCzfC3hRGAm0PlvxiRzfG0NAZNS5ehCkOHB12dWJKPml2kX2131GWIA/YcAFZcbcGZ3YHhV/CmqTgsNCduac1eFpLrSIzJbeyNkNY2ljaCi7sbc+DNpswIDAQAB
  9. #SHA1withRsa对应支付宝公钥
  10. #alipay_public_key = MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDI6d306Q8fIfCOaTXyiUeJHkrIvYISRcc73s3vF1ZT7XN8RNPwJxo8pWaJMmvyTn9N4HQ632qJBVHf8sxHi/fEsraprwCtzvzQETrNRwVxLO5jVmRGi60j8Ue1efIlzPXV9je9mkjzOmdssymZkh2QhUrCmZYI/FCEa3/cNMW0QIDAQAB
  11. #SHA256withRsa对应支付宝公钥
  12. alipay_public_key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqzWgVL/NWrJAeyEImwtaK3IDwj0dKkqUDIfqqWn5SiLaWMYi9RmKhn+jY9VM7JXEIkYYeVlqIL6Xn7OvYFRTi4buTCXGKvFLn95aDcaur77/S/0ibcdN1K2wIoHzaqQhXAb1ezKxTnFP7OLJsAL22b0NzrQDj2OH9SA06gJb8nHBfR+7Sx7DfwcqE0OtTcDHjbbcB24Qgg/dfItxoEnKuSyRVrf6BtpUnJxSzG/Ge7FfF+VBq8re1t4ZTSxaDEjto071I5VFBxr7I4SyqZsc7WpAmZL8AqUgEbQ1XYBWx2LnpJXM5GQW/thUvcDDqzea7LJNWJOQPM5DaZQgu7QuuwIDAQAB
  13. # 签名类型: RSA->SHA1withRsa,RSA2->SHA256withRsa
  14. sign_type = RSA2
  15. # 当面付最大查询次数和查询间隔(毫秒)
  16. max_query_retry = 5
  17. query_duration = 5000
  18. # 当面付最大撤销次数和撤销间隔(毫秒)
  19. max_cancel_retry = 3
  20. cancel_duration = 2000
  21. # 交易保障线程第一次调度延迟和调度间隔(秒)
  22. heartbeat_delay = 5
  23. heartbeat_duration = 900

配置回调url

两次回调,扫码进行一次回调,扫码付款成功进行一次回调

生成二维码,上传到ftp服务器

OrderServiceImpl.java

  1. package com.mmall.service.impl;
  2. /**
  3. * Created by geely
  4. */
  5. @Service("iOrderService")
  6. public class OrderServiceImpl implements IOrderService {
  7. private static AlipayTradeService tradeService;
  8. static {
  9. /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
  10. * Configs会读取classpath下的zfbinfo.properties文件配置信息,如果找不到该文件则确认该文件是否在classpath目录
  11. */
  12. Configs.init("zfbinfo.properties");
  13. /** 使用Configs提供的默认参数
  14. * AlipayTradeService可以使用单例或者为静态成员对象,不需要反复new
  15. */
  16. tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();
  17. }
  18. private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
  19. @Autowired
  20. private OrderMapper orderMapper;
  21. @Autowired
  22. private OrderItemMapper orderItemMapper;
  23. @Autowired
  24. private PayInfoMapper payInfoMapper;
  25. @Autowired
  26. private CartMapper cartMapper;
  27. @Autowired
  28. private ProductMapper productMapper;
  29. @Autowired
  30. private ShippingMapper shippingMapper;
  31. public ServerResponse pay(Long orderNo,Integer userId,String path){
  32. Map<String ,String> resultMap = Maps.newHashMap();
  33. Order order = orderMapper.selectByUserIdAndOrderNo(userId,orderNo);
  34. if(order == null){
  35. return ServerResponse.createByErrorMessage("用户没有该订单");
  36. }
  37. resultMap.put("orderNo",String.valueOf(order.getOrderNo()));
  38. // (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、数字、下划线,
  39. // 需保证商户系统端不能重复,建议通过数据库sequence生成,
  40. String outTradeNo = order.getOrderNo().toString();
  41. // (必填) 订单标题,粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费”
  42. String subject = new StringBuilder().append("happymmall扫码支付,订单号:").append(outTradeNo).toString();
  43. // (必填) 订单总金额,单位为元,不能超过1亿元
  44. // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
  45. String totalAmount = order.getPayment().toString();
  46. // (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段
  47. // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
  48. String undiscountableAmount = "0";
  49. // 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号)
  50. // 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID
  51. String sellerId = "";
  52. // 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元"
  53. String body = new StringBuilder().append("订单").append(outTradeNo).append("购买商品共").append(totalAmount).append("元").toString();
  54. // 商户操作员编号,添加此参数可以为商户操作员做销售统计
  55. String operatorId = "test_operator_id";
  56. // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持
  57. String storeId = "test_store_id";
  58. // 业务扩展参数,目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法),详情请咨询支付宝技术支持
  59. ExtendParams extendParams = new ExtendParams();
  60. extendParams.setSysServiceProviderId("2088100200300400500");
  61. // 支付超时,定义为120分钟
  62. String timeoutExpress = "120m";
  63. // 商品明细列表,需填写购买商品详细信息,
  64. List<GoodsDetail> goodsDetailList = new ArrayList<GoodsDetail>();
  65. List<OrderItem> orderItemList = orderItemMapper.getByOrderNoUserId(orderNo,userId);
  66. for(OrderItem orderItem : orderItemList){
  67. GoodsDetail goods = GoodsDetail.newInstance(orderItem.getProductId().toString(), orderItem.getProductName(),
  68. BigDecimalUtil.mul(orderItem.getCurrentUnitPrice().doubleValue(),new Double(100).doubleValue()).longValue(),
  69. orderItem.getQuantity());
  70. goodsDetailList.add(goods);
  71. }
  72. // 创建扫码支付请求builder,设置请求参数
  73. AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
  74. .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo)
  75. .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
  76. .setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams)
  77. .setTimeoutExpress(timeoutExpress)
  78. .setNotifyUrl(PropertiesUtil.getProperty("alipay.callback.url"))//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
  79. .setGoodsDetailList(goodsDetailList);
  80. AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
  81. switch (result.getTradeStatus()) {
  82. case SUCCESS:
  83. logger.info("支付宝预下单成功: )");
  84. AlipayTradePrecreateResponse response = result.getResponse();
  85. dumpResponse(response);
  86. File folder = new File(path);
  87. if(!folder.exists()){
  88. folder.setWritable(true);
  89. folder.mkdirs();
  90. }
  91. // 需要修改为运行机器上的路径
  92. //细节细节细节
  93. String qrPath = String.format(path+"/qr-%s.png",response.getOutTradeNo());
  94. String qrFileName = String.format("qr-%s.png",response.getOutTradeNo());
  95. ZxingUtils.getQRCodeImge(response.getQrCode(), 256, qrPath);
  96. File targetFile = new File(path,qrFileName);
  97. try {
  98. FTPUtil.uploadFile(Lists.newArrayList(targetFile));
  99. } catch (IOException e) {
  100. logger.error("上传二维码异常",e);
  101. }
  102. logger.info("qrPath:" + qrPath);
  103. String qrUrl = PropertiesUtil.getProperty("ftp.server.http.prefix")+targetFile.getName();
  104. resultMap.put("qrUrl",qrUrl);
  105. return ServerResponse.createBySuccess(resultMap);
  106. case FAILED:
  107. logger.error("支付宝预下单失败!!!");
  108. return ServerResponse.createByErrorMessage("支付宝预下单失败!!!");
  109. case UNKNOWN:
  110. logger.error("系统异常,预下单状态未知!!!");
  111. return ServerResponse.createByErrorMessage("系统异常,预下单状态未知!!!");
  112. default:
  113. logger.error("不支持的交易状态,交易返回异常!!!");
  114. return ServerResponse.createByErrorMessage("不支持的交易状态,交易返回异常!!!");
  115. }
  116. }
  117. // 简单打印应答
  118. private void dumpResponse(AlipayResponse response) {
  119. if (response != null) {
  120. logger.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
  121. if (StringUtils.isNotEmpty(response.getSubCode())) {
  122. logger.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
  123. response.getSubMsg()));
  124. }
  125. logger.info("body:" + response.getBody());
  126. }
  127. }
  128. public ServerResponse aliCallback(Map<String,String> params){
  129. Long orderNo = Long.parseLong(params.get("out_trade_no"));
  130. String tradeNo = params.get("trade_no");
  131. String tradeStatus = params.get("trade_status");
  132. Order order = orderMapper.selectByOrderNo(orderNo);
  133. if(order == null){
  134. return ServerResponse.createByErrorMessage("非快乐慕商城的订单,回调忽略");
  135. }
  136. if(order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){
  137. return ServerResponse.createBySuccess("支付宝重复调用");
  138. }
  139. if(Const.AlipayCallback.TRADE_STATUS_TRADE_SUCCESS.equals(tradeStatus)){
  140. order.setPaymentTime(DateTimeUtil.strToDate(params.get("gmt_payment")));
  141. order.setStatus(Const.OrderStatusEnum.PAID.getCode());
  142. orderMapper.updateByPrimaryKeySelective(order);
  143. }
  144. PayInfo payInfo = new PayInfo();
  145. payInfo.setUserId(order.getUserId());
  146. payInfo.setOrderNo(order.getOrderNo());
  147. payInfo.setPayPlatform(Const.PayPlatformEnum.ALIPAY.getCode());
  148. payInfo.setPlatformNumber(tradeNo);
  149. payInfo.setPlatformStatus(tradeStatus);
  150. payInfoMapper.insert(payInfo);
  151. return ServerResponse.createBySuccess();
  152. }
  153. public ServerResponse queryOrderPayStatus(Integer userId,Long orderNo){
  154. Order order = orderMapper.selectByUserIdAndOrderNo(userId,orderNo);
  155. if(order == null){
  156. return ServerResponse.createByErrorMessage("用户没有该订单");
  157. }
  158. if(order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){
  159. return ServerResponse.createBySuccess();
  160. }
  161. return ServerResponse.createByError();
  162. }
  163. }

NATAPP1分钟快速新手图文教程

本文由博客一文多发平台 OpenWrite 发布!

版权声明:本文为lisingshen原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/lisingshen/p/11794495.html