CREATE TABLE `mmall_user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户表id', `username` varchar(50) NOT NULL COMMENT '用户名', `password` varchar(50) NOT NULL COMMENT '用户密码,MD5加密', `email` varchar(50) DEFAULT NULL, `phone` varchar(20) DEFAULT NULL, `question` varchar(100) DEFAULT NULL COMMENT '找回密码问题', `answer` varchar(100) DEFAULT NULL COMMENT '找回密码答案', `role` int(4) NOT NULL COMMENT '角色0-管理员,1-普通用户', `create_time` datetime NOT NULL COMMENT '创建时间', `update_time` datetime NOT NULL COMMENT '最后一次更新时间', PRIMARY KEY (`id`), UNIQUE KEY `user_name_unique` (`username`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8; 复制代码
CREATE TABLE `mmall_order_item` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单子表id', `user_id` int(11) DEFAULT NULL, `order_no` bigint(20) DEFAULT NULL, `product_id` int(11) DEFAULT NULL COMMENT '商品id', `product_name` varchar(100) DEFAULT NULL COMMENT '商品名称', `product_image` varchar(500) DEFAULT NULL COMMENT '商品图片地址', `current_unit_price` decimal(20,2) DEFAULT NULL COMMENT '生成订单时的商品单价,单位是元,保留两位小数', `quantity` int(10) DEFAULT NULL COMMENT '商品数量', `total_price` decimal(20,2) DEFAULT NULL COMMENT '商品总价,单位是元,保留两位小数', `create_time` datetime DEFAULT NULL, `update_time` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `order_no_index` (`order_no`) USING BTREE, KEY `order_no_user_id_index` (`user_id`,`order_no`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=135 DEFAULT CHARSET=utf8; 复制代码
create_time
数据创建时间 update_time
数据更新时间
mybatis-generator
自动化生成数据库交互代码
配置pom.xml
<build> <finalName>mmall</finalName> <plugins> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.2</version> <configuration> <verbose>true</verbose> <overwrite>true</overwrite> </configuration> </plugin> </build> 复制代码
datasource.properties
db.driverLocation=/Users/imooc/mysql-connector-java-5.1.6-bin.jar db.driverClassName=com.mysql.jdbc.Driver #db.url=jdbc:mysql://192.1.1.1:3306/mmall?characterEncoding=utf-8 db.url=jdbc:mysql://你的数据库IP:你的数据库Port/你的database?characterEncoding=utf-8 db.username=mmall db.password=dbpassword db.initialSize = 20 db.maxActive = 50 db.maxIdle = 20 db.minIdle = 10 db.maxWait = 10 db.defaultAutoCommit = true db.minEvictableIdleTimeMillis = 3600000 复制代码
generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <!--导入属性配置--> <properties resource="datasource.properties"></properties> <!--指定特定数据库的jdbc驱动jar包的位置--> <classPathEntry location="${db.driverLocation}"/> <context id="default" targetRuntime="MyBatis3"> <!-- optional,旨在创建class时,对注释进行控制 --> <commentGenerator> <property name="suppressDate" value="true"/> <property name="suppressAllComments" value="true"/> </commentGenerator> <!--jdbc的数据库连接 --> <jdbcConnection driverClass="${db.driverClassName}" connectionURL="${db.url}" userId="${db.username}" password="${db.password}"> </jdbcConnection> <!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制--> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- Model模型生成器,用来生成含有主键key的类,记录类 以及查询Example类 targetPackage 指定生成的model生成所在的包名 targetProject 指定在该项目下所在的路径 --> <!--<javaModelGenerator targetPackage="com.mmall.pojo" targetProject="./src/main/java">--> <javaModelGenerator targetPackage="com.mmall.pojo" targetProject="./src/main/java"> <!-- 是否允许子包,即targetPackage.schemaName.tableName --> <property name="enableSubPackages" value="false"/> <!-- 是否对model添加 构造函数 --> <property name="constructorBased" value="true"/> <!-- 是否对类CHAR类型的列的数据进行trim操作 --> <property name="trimStrings" value="true"/> <!-- 建立的Model对象是否 不可改变 即生成的Model对象不会有 setter方法,只有构造方法 --> <property name="immutable" value="false"/> </javaModelGenerator> <!--mapper映射文件生成所在的目录 为每一个数据库的表生成对应的SqlMap文件 --> <!--<sqlMapGenerator targetPackage="mappers" targetProject="./src/main/resources">--> <sqlMapGenerator targetPackage="mappers" targetProject="./src/main/resources"> <property name="enableSubPackages" value="false"/> </sqlMapGenerator> <!-- 客户端代码,生成易于使用的针对Model对象和XML配置文件 的代码 type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象 type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象 type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口 --> <!-- targetPackage:mapper接口dao生成的位置 --> <!--<javaClientGenerator type="XMLMAPPER" targetPackage="com.mmall.dao" targetProject="./src/main/java">--> <javaClientGenerator type="XMLMAPPER" targetPackage="com.mmall.dao" targetProject="./src/main/java"> <!-- enableSubPackages:是否让schema作为包的后缀 --> <property name="enableSubPackages" value="false" /> </javaClientGenerator> <table tableName="mmall_shipping" domainObjectName="Shipping" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> <table tableName="mmall_cart" domainObjectName="Cart" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> <table tableName="mmall_cart_item" domainObjectName="CartItem" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> <table tableName="mmall_category" domainObjectName="Category" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> <table tableName="mmall_order" domainObjectName="Order" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> <table tableName="mmall_order_item" domainObjectName="OrderItem" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> <table tableName="mmall_pay_info" domainObjectName="PayInfo" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> <table tableName="mmall_product" domainObjectName="Product" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"> <columnOverride column="detail" jdbcType="VARCHAR" /> <columnOverride column="sub_images" jdbcType="VARCHAR" /> </table> <table tableName="mmall_user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> <!-- geelynote mybatis插件的搭建 --> </context> </generatorConfiguration> 复制代码
运行
mybatis-plugin
idea插件,实现mybatis的接口文件和xml自动跳转
下载
mybatis-pagehelper
mybatis分页组件
配置 pom.xml
<!-- mybatis pager --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>com.github.miemiedev</groupId> <artifactId>mybatis-paginator</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>0.9.4</version> </dependency> 复制代码
方式一:配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list> <!-- 启动我们自己的listener --> <listener> <listener-class>com.atguigu.scw.manager.listener.MyAppListener</listener-class> </listener> <!-- 启动spring容器 --> <!-- needed for ContextLoaderListener --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-*.xml</param-value> </context-param> <!-- Bootstraps the root web application context before servlet initialization --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- The front controller of this Spring Web application, responsible for handling all application requests --> <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- Map all requests to the DispatcherServlet for handling --> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 加上字符编码过滤器 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!-- 只是指定了编码格式 --> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <!-- 进行请求乱码解决 --> <init-param> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app> 复制代码
方式二:配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>Archetype Created Web Application</display-name> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:applicationContext.xml </param-value> </context-param> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app> 复制代码
FeHelper
Restlet Client
入参需要指定当前用户id
盐值加密
MD5Util.java
package com.mmall.util; import org.springframework.util.StringUtils; import java.security.MessageDigest; /** * Created by geely */ public class MD5Util { private static String byteArrayToHexString(byte b[]) { StringBuffer resultSb = new StringBuffer(); for (int i = 0; i < b.length; i++) resultSb.append(byteToHexString(b[i])); return resultSb.toString(); } private static String byteToHexString(byte b) { int n = b; if (n < 0) n += 256; int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } /** * 返回大写MD5 * * @param origin * @param charsetname * @return */ private static String MD5Encode(String origin, String charsetname) { String resultString = null; try { resultString = new String(origin); MessageDigest md = MessageDigest.getInstance("MD5"); if (charsetname == null || "".equals(charsetname)) resultString = byteArrayToHexString(md.digest(resultString.getBytes())); else resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname))); } catch (Exception exception) { } return resultString.toUpperCase(); } public static String MD5EncodeUtf8(String origin) { origin = origin + PropertiesUtil.getProperty("password.salt", ""); return MD5Encode(origin, "utf-8"); } private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; } 复制代码
PropertiesUtil.java
读取src/main/resources目录下的配置文件
package com.mmall.util; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStreamReader; import java.util.Properties; /** * Created by geely */ public class PropertiesUtil { private static Logger logger = LoggerFactory.getLogger(PropertiesUtil.class); private static Properties props; static { String fileName = "mmall.properties"; props = new Properties(); try { props.load(new InputStreamReader(PropertiesUtil.class.getClassLoader().getResourceAsStream(fileName),"UTF-8")); } catch (IOException e) { logger.error("配置文件读取异常",e); } } public static String getProperty(String key){ String value = props.getProperty(key.trim()); if(StringUtils.isBlank(value)){ return null; } return value.trim(); } public static String getProperty(String key,String defaultValue){ String value = props.getProperty(key.trim()); if(StringUtils.isBlank(value)){ value = defaultValue; } return value.trim(); } } 复制代码
mmall.properties
ftp.server.ip=你的FTP服务器ip地址 ftp.user=mmallftp ftp.pass=ftppassword ftp.server.http.prefix=http://img.happymmall.com/ alipay.callback.url=http://www.happymmall.com/order/alipay_callback.do password.salt = geelysdafaqj23ou89ZXcj@#$@#$#@KJdjklj;D../dSF., 复制代码
应用:明文加密
设置token并传给前台用户
验证token
TokenCache.java
package com.mmall.common; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.TimeUnit; /** * Created by geely */ public class TokenCache { private static Logger logger = LoggerFactory.getLogger(TokenCache.class); public static final String TOKEN_PREFIX = "token_"; //LRU算法 private static LoadingCache<String,String> localCache = CacheBuilder.newBuilder().initialCapacity(1000).maximumSize(10000).expireAfterAccess(12, TimeUnit.HOURS) .build(new CacheLoader<String, String>() { //默认的数据加载实现,当调用get取值的时候,如果key没有对应的值,就调用这个方法进行加载. @Override public String load(String s) throws Exception { return "null"; } }); public static void setKey(String key,String value){ localCache.put(key,value); } public static String getKey(String key){ String value = null; try { value = localCache.get(key); if("null".equals(value)){ return null; } return value; }catch (Exception e){ logger.error("localCache get error",e); } return null; } } 复制代码
UserServiceImpl.java
public ServerResponse<String> checkAnswer(String username,String question,String answer){ int resultCount = userMapper.checkAnswer(username,question,answer); if(resultCount>0){ //说明问题及问题答案是这个用户的,并且是正确的 String forgetToken = UUID.randomUUID().toString(); TokenCache.setKey(TokenCache.TOKEN_PREFIX+username,forgetToken); return ServerResponse.createBySuccess(forgetToken); } return ServerResponse.createByErrorMessage("问题的答案错误"); } public ServerResponse<String> forgetResetPassword(String username,String passwordNew,String forgetToken){ if(org.apache.commons.lang3.StringUtils.isBlank(forgetToken)){ return ServerResponse.createByErrorMessage("参数错误,token需要传递"); } ServerResponse validResponse = this.checkValid(username,Const.USERNAME); if(validResponse.isSuccess()){ //用户不存在 return ServerResponse.createByErrorMessage("用户不存在"); } String token = TokenCache.getKey(TokenCache.TOKEN_PREFIX+username); if(org.apache.commons.lang3.StringUtils.isBlank(token)){ return ServerResponse.createByErrorMessage("token无效或者过期"); } if(org.apache.commons.lang3.StringUtils.equals(forgetToken,token)){ String md5Password = MD5Util.MD5EncodeUtf8(passwordNew); int rowCount = userMapper.updatePasswordByUsername(username,md5Password); if(rowCount > 0){ return ServerResponse.createBySuccessMessage("修改密码成功"); } }else{ return ServerResponse.createByErrorMessage("token错误,请重新获取重置密码的token"); } return ServerResponse.createByErrorMessage("修改密码失败"); } 复制代码
ServerResponse.java
package com.mmall.common; import org.codehaus.jackson.annotate.JsonIgnore; import org.codehaus.jackson.map.annotate.JsonSerialize; import java.io.Serializable; /** * Created by geely */ @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) //保证序列化json的时候,如果是null的对象,key也会消失 public class ServerResponse<T> implements Serializable { private int status; private String msg; private T data; private ServerResponse(int status){ this.status = status; } private ServerResponse(int status,T data){ this.status = status; this.data = data; } private ServerResponse(int status,String msg,T data){ this.status = status; this.msg = msg; this.data = data; } private ServerResponse(int status,String msg){ this.status = status; this.msg = msg; } @JsonIgnore //使之不在json序列化结果当中 public boolean isSuccess(){ return this.status == ResponseCode.SUCCESS.getCode(); } public int getStatus(){ return status; } public T getData(){ return data; } public String getMsg(){ return msg; } public static <T> ServerResponse<T> createBySuccess(){ return new ServerResponse<T>(ResponseCode.SUCCESS.getCode()); } public static <T> ServerResponse<T> createBySuccessMessage(String msg){ return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(),msg); } public static <T> ServerResponse<T> createBySuccess(T data){ return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(),data); } public static <T> ServerResponse<T> createBySuccess(String msg,T data){ return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(),msg,data); } public static <T> ServerResponse<T> createByError(){ return new ServerResponse<T>(ResponseCode.ERROR.getCode(),ResponseCode.ERROR.getDesc()); } public static <T> ServerResponse<T> createByErrorMessage(String errorMessage){ return new ServerResponse<T>(ResponseCode.ERROR.getCode(),errorMessage); } public static <T> ServerResponse<T> createByErrorCodeMessage(int errorCode,String errorMessage){ return new ServerResponse<T>(errorCode,errorMessage); } } 复制代码
ResponseCode.java
package com.mmall.common; /** * Created by geely */ public enum ResponseCode { SUCCESS(0,"SUCCESS"), ERROR(1,"ERROR"), NEED_LOGIN(10,"NEED_LOGIN"), ILLEGAL_ARGUMENT(2,"ILLEGAL_ARGUMENT"); private final int code; private final String desc; ResponseCode(int code,String desc){ this.code = code; this.desc = desc; } public int getCode(){ return code; } public String getDesc(){ return desc; } } 复制代码
/** * 递归查询本节点的id及孩子节点的id * @param categoryId * @return */ public ServerResponse<List<Integer>> selectCategoryAndChildrenById(Integer categoryId){ Set<Category> categorySet = Sets.newHashSet(); findChildCategory(categorySet,categoryId); List<Integer> categoryIdList = Lists.newArrayList(); if(categoryId != null){ for(Category categoryItem : categorySet){ categoryIdList.add(categoryItem.getId()); } } return ServerResponse.createBySuccess(categoryIdList); } //递归算法,算出子节点 private Set<Category> findChildCategory(Set<Category> categorySet ,Integer categoryId){ Category category = categoryMapper.selectByPrimaryKey(categoryId); if(category != null){ categorySet.add(category); } //查找子节点,递归算法一定要有一个退出的条件 List<Category> categoryList = categoryMapper.selectCategoryChildrenByParentId(categoryId); for(Category categoryItem : categoryList){ findChildCategory(categorySet,categoryItem.getId()); } return categorySet; } 复制代码
Set集合
重写自定义对象Category的 equals
和 hashCode
方法
Product.java
package com.mmall.pojo; import java.math.BigDecimal; import java.util.Date; public class Product { private Integer id; private Integer categoryId; private String name; private String subtitle; private String mainImage; private String subImages; private String detail; private BigDecimal price; private Integer stock; private Integer status; private Date createTime; private Date updateTime; 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) { this.id = id; this.categoryId = categoryId; this.name = name; this.subtitle = subtitle; this.mainImage = mainImage; this.subImages = subImages; this.detail = detail; this.price = price; this.stock = stock; this.status = status; this.createTime = createTime; this.updateTime = updateTime; } public Product() { super(); } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getCategoryId() { return categoryId; } public void setCategoryId(Integer categoryId) { this.categoryId = categoryId; } public String getName() { return name; } public void setName(String name) { this.name = name == null ? null : name.trim(); } public String getSubtitle() { return subtitle; } public void setSubtitle(String subtitle) { this.subtitle = subtitle == null ? null : subtitle.trim(); } public String getMainImage() { return mainImage; } public void setMainImage(String mainImage) { this.mainImage = mainImage == null ? null : mainImage.trim(); } public String getSubImages() { return subImages; } public void setSubImages(String subImages) { this.subImages = subImages == null ? null : subImages.trim(); } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail == null ? null : detail.trim(); } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } public Integer getStock() { return stock; } public void setStock(Integer stock) { this.stock = stock; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public Date getUpdateTime() { return updateTime; } public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } } 复制代码
ProductDetailVo.java
package com.mmall.vo; import java.math.BigDecimal; /** * Created by geely */ public class ProductDetailVo { private Integer id; private Integer categoryId; private String name; private String subtitle; private String mainImage; private String subImages; private String detail; private BigDecimal price; private Integer stock; private Integer status; private String createTime; private String updateTime; private String imageHost; private Integer parentCategoryId; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getCategoryId() { return categoryId; } public void setCategoryId(Integer categoryId) { this.categoryId = categoryId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSubtitle() { return subtitle; } public void setSubtitle(String subtitle) { this.subtitle = subtitle; } public String getMainImage() { return mainImage; } public void setMainImage(String mainImage) { this.mainImage = mainImage; } public String getSubImages() { return subImages; } public void setSubImages(String subImages) { this.subImages = subImages; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } public Integer getStock() { return stock; } public void setStock(Integer stock) { this.stock = stock; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public String getCreateTime() { return createTime; } public void setCreateTime(String createTime) { this.createTime = createTime; } public String getUpdateTime() { return updateTime; } public void setUpdateTime(String updateTime) { this.updateTime = updateTime; } public String getImageHost() { return imageHost; } public void setImageHost(String imageHost) { this.imageHost = imageHost; } public Integer getParentCategoryId() { return parentCategoryId; } public void setParentCategoryId(Integer parentCategoryId) { this.parentCategoryId = parentCategoryId; } } 复制代码
Tomcat启动加载静态代码块
DateTimeUtil.java
package com.mmall.util; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import java.util.Date; /** * Created by geely */ public class DateTimeUtil { //joda-time //str->Date //Date->str public static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss"; public static Date strToDate(String dateTimeStr,String formatStr){ DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(formatStr); DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr); return dateTime.toDate(); } public static String dateToStr(Date date,String formatStr){ if(date == null){ return StringUtils.EMPTY; } DateTime dateTime = new DateTime(date); return dateTime.toString(formatStr); } public static Date strToDate(String dateTimeStr){ DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(STANDARD_FORMAT); DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr); return dateTime.toDate(); } public static String dateToStr(Date date){ if(date == null){ return StringUtils.EMPTY; } DateTime dateTime = new DateTime(date); return dateTime.toString(STANDARD_FORMAT); } public static void main(String[] args) { System.out.println(DateTimeUtil.dateToStr(new Date(),"yyyy-MM-dd HH:mm:ss")); System.out.println(DateTimeUtil.strToDate("2010-01-01 11:11:11","yyyy-MM-dd HH:mm:ss")); } } 复制代码
配置pom.xml
实现
先将文件上传到本地======>上传到远程ftp====>删除本地文件
配置 pom.xml
<!-- file upload --> <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.0.1</version> </dependency> 复制代码
配置 dispatcher-servlet.xml
<!-- 文件上传 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760"/> <!-- 10m --> <property name="maxInMemorySize" value="4096" /> <property name="defaultEncoding" value="UTF-8"></property> </bean> 复制代码
FileServiceImpl.java
package com.mmall.service.impl; import com.google.common.collect.Lists; import com.mmall.service.IFileService; import com.mmall.util.FTPUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.util.UUID; /** * Created by geely */ @Service("iFileService") public class FileServiceImpl implements IFileService { private Logger logger = LoggerFactory.getLogger(FileServiceImpl.class); public String upload(MultipartFile file,String path){ String fileName = file.getOriginalFilename(); //扩展名 //abc.jpg String fileExtensionName = fileName.substring(fileName.lastIndexOf(".")+1); String uploadFileName = UUID.randomUUID().toString()+"."+fileExtensionName; logger.info("开始上传文件,上传文件的文件名:{},上传的路径:{},新文件名:{}",fileName,path,uploadFileName); File fileDir = new File(path); if(!fileDir.exists()){ fileDir.setWritable(true); fileDir.mkdirs(); } File targetFile = new File(path,uploadFileName); try { file.transferTo(targetFile); //文件已经上传成功了 FTPUtil.uploadFile(Lists.newArrayList(targetFile)); //已经上传到ftp服务器上 targetFile.delete(); } catch (IOException e) { logger.error("上传文件异常",e); return null; } //A:abc.jpg //B:abc.jpg return targetFile.getName(); } } 复制代码
连接远程ftp,上传文件
FTPUtil.java
package com.mmall.util; import org.apache.commons.net.ftp.FTPClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.List; /** * Created by geely */ public class FTPUtil { private static final Logger logger = LoggerFactory.getLogger(FTPUtil.class); private static String ftpIp = PropertiesUtil.getProperty("ftp.server.ip"); private static String ftpUser = PropertiesUtil.getProperty("ftp.user"); private static String ftpPass = PropertiesUtil.getProperty("ftp.pass"); public FTPUtil(String ip,int port,String user,String pwd){ this.ip = ip; this.port = port; this.user = user; this.pwd = pwd; } public static boolean uploadFile(List<File> fileList) throws IOException { FTPUtil ftpUtil = new FTPUtil(ftpIp,21,ftpUser,ftpPass); logger.info("开始连接ftp服务器"); boolean result = ftpUtil.uploadFile("img",fileList); logger.info("开始连接ftp服务器,结束上传,上传结果:{}"); return result; } private boolean uploadFile(String remotePath,List<File> fileList) throws IOException { boolean uploaded = true; FileInputStream fis = null; //连接FTP服务器 if(connectServer(this.ip,this.port,this.user,this.pwd)){ try { ftpClient.changeWorkingDirectory(remotePath); ftpClient.setBufferSize(1024); ftpClient.setControlEncoding("UTF-8"); ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); ftpClient.enterLocalPassiveMode(); for(File fileItem : fileList){ fis = new FileInputStream(fileItem); ftpClient.storeFile(fileItem.getName(),fis); } } catch (IOException e) { logger.error("上传文件异常",e); uploaded = false; e.printStackTrace(); } finally { fis.close(); ftpClient.disconnect(); } } return uploaded; } private boolean connectServer(String ip,int port,String user,String pwd){ boolean isSuccess = false; ftpClient = new FTPClient(); try { ftpClient.connect(ip); isSuccess = ftpClient.login(user,pwd); } catch (IOException e) { logger.error("连接FTP服务器异常",e); } return isSuccess; } private String ip; private int port; private String user; private String pwd; private FTPClient ftpClient; public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public FTPClient getFtpClient() { return ftpClient; } public void setFtpClient(FTPClient ftpClient) { this.ftpClient = ftpClient; } } 复制代码
和ftp文件上传类似,只是对返回值有特殊要求
package com.mmall.util; import java.math.BigDecimal; /** * Created by geely */ public class BigDecimalUtil { private BigDecimalUtil(){ } public static BigDecimal add(double v1,double v2){ BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.add(b2); } public static BigDecimal sub(double v1,double v2){ BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.subtract(b2); } public static BigDecimal mul(double v1,double v2){ BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.multiply(b2); } public static BigDecimal div(double v1,double v2){ BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.divide(b2,2,BigDecimal.ROUND_HALF_UP);//四舍五入,保留2位小数 //除不尽的情况 } } 复制代码
一定要用 BigDecimal
的 String
构造函数
public class BigDecimalTest { @Test public void test1(){ System.out.println(0.05+0.01); System.out.println(1.0-0.42); System.out.println(4.015*100); System.out.println(123.3/100); } @Test public void test2(){ BigDecimal b1 = new BigDecimal(0.05); BigDecimal b2 = new BigDecimal(0.01); System.out.println(b1.add(b2)); } @Test public void test3(){ BigDecimal b1 = new BigDecimal("0.05"); BigDecimal b2 = new BigDecimal("0.01"); System.out.println(b1.add(b2)); } } 复制代码
Const.java
package com.mmall.common; import com.google.common.collect.Sets; import java.util.Set; /** * Created by geely */ public class Const { public static final String CURRENT_USER = "currentUser"; public static final String EMAIL = "email"; public static final String USERNAME = "username"; public interface ProductListOrderBy{ Set<String> PRICE_ASC_DESC = Sets.newHashSet("price_desc","price_asc"); } public interface Cart{ int CHECKED = 1;//即购物车选中状态 int UN_CHECKED = 0;//购物车中未选中状态 String LIMIT_NUM_FAIL = "LIMIT_NUM_FAIL"; String LIMIT_NUM_SUCCESS = "LIMIT_NUM_SUCCESS"; } public interface Role{ int ROLE_CUSTOMER = 0; //普通用户 int ROLE_ADMIN = 1;//管理员 } public enum ProductStatusEnum{ ON_SALE(1,"在线"); private String value; private int code; ProductStatusEnum(int code,String value){ this.code = code; this.value = value; } public String getValue() { return value; } public int getCode() { return code; } } public enum OrderStatusEnum{ CANCELED(0,"已取消"), NO_PAY(10,"未支付"), PAID(20,"已付款"), SHIPPED(40,"已发货"), ORDER_SUCCESS(50,"订单完成"), ORDER_CLOSE(60,"订单关闭"); OrderStatusEnum(int code,String value){ this.code = code; this.value = value; } private String value; private int code; public String getValue() { return value; } public int getCode() { return code; } public static OrderStatusEnum codeOf(int code){ for(OrderStatusEnum orderStatusEnum : values()){ if(orderStatusEnum.getCode() == code){ return orderStatusEnum; } } throw new RuntimeException("么有找到对应的枚举"); } } public interface AlipayCallback{ String TRADE_STATUS_WAIT_BUYER_PAY = "WAIT_BUYER_PAY"; String TRADE_STATUS_TRADE_SUCCESS = "TRADE_SUCCESS"; String RESPONSE_SUCCESS = "success"; String RESPONSE_FAILED = "failed"; } public enum PayPlatformEnum{ ALIPAY(1,"支付宝"); PayPlatformEnum(int code,String value){ this.code = code; this.value = value; } private String value; private int code; public String getValue() { return value; } public int getCode() { return code; } } public enum PaymentTypeEnum{ ONLINE_PAY(1,"在线支付"); PaymentTypeEnum(int code,String value){ this.code = code; this.value = value; } private String value; private int code; public String getValue() { return value; } public int getCode() { return code; } public static PaymentTypeEnum codeOf(int code){ for(PaymentTypeEnum paymentTypeEnum : values()){ if(paymentTypeEnum.getCode() == code){ return paymentTypeEnum; } } throw new RuntimeException("么有找到对应的枚举"); } } } 复制代码
使用
收货地址对象必须要有 get
和 set
方法
当面付
当面付Demo
服务端SDK下载和使用教程
沙箱环境使用
生成RSA密钥
导入依赖
配置maven插件,除了 pom.xml
配置的依赖,lib包中的依赖也会一起打包部署
配置沙箱环境 zfbinfo.properties
# 支付宝网关名、partnerId和appId open_api_domain = https://openapi.alipaydev.com/gateway.do mcloud_api_domain = http://mcloudmonitor.com/gateway.do pid = 2088102180444972 appid = 2016102100728313 # RSA私钥、公钥和支付宝公钥 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 public_key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAikNqRCM1zOCKDdXDMzhV3ZZPMlV9nCl1iE2fdhBgEEHEcrWldO8kDms91BPSk3k/TbutvBvh2TLCVMUIxFBE2oJmOZy7W3i9+TNlHIm2KTN3toFU7VFvOggOuRgnS81IXSLoPMn9hfc1mssxuLB2fQ3E3sxumYxbvhLQ6RYIPgramO5/4oY0yKnhNZV9AtmSCqSGLO0I0fAM7Qf6kXKTiSkXzChg4Jk/RgCzfC3hRGAm0PlvxiRzfG0NAZNS5ehCkOHB12dWJKPml2kX2131GWIA/YcAFZcbcGZ3YHhV/CmqTgsNCduac1eFpLrSIzJbeyNkNY2ljaCi7sbc+DNpswIDAQAB #SHA1withRsa对应支付宝公钥 #alipay_public_key = MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDI6d306Q8fIfCOaTXyiUeJHkrIvYISRcc73s3vF1ZT7XN8RNPwJxo8pWaJMmvyTn9N4HQ632qJBVHf8sxHi/fEsraprwCtzvzQETrNRwVxLO5jVmRGi60j8Ue1efIlzPXV9je9mkjzOmdssymZkh2QhUrCmZYI/FCEa3/cNMW0QIDAQAB #SHA256withRsa对应支付宝公钥 alipay_public_key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqzWgVL/NWrJAeyEImwtaK3IDwj0dKkqUDIfqqWn5SiLaWMYi9RmKhn+jY9VM7JXEIkYYeVlqIL6Xn7OvYFRTi4buTCXGKvFLn95aDcaur77/S/0ibcdN1K2wIoHzaqQhXAb1ezKxTnFP7OLJsAL22b0NzrQDj2OH9SA06gJb8nHBfR+7Sx7DfwcqE0OtTcDHjbbcB24Qgg/dfItxoEnKuSyRVrf6BtpUnJxSzG/Ge7FfF+VBq8re1t4ZTSxaDEjto071I5VFBxr7I4SyqZsc7WpAmZL8AqUgEbQ1XYBWx2LnpJXM5GQW/thUvcDDqzea7LJNWJOQPM5DaZQgu7QuuwIDAQAB # 签名类型: RSA->SHA1withRsa,RSA2->SHA256withRsa sign_type = RSA2 # 当面付最大查询次数和查询间隔(毫秒) max_query_retry = 5 query_duration = 5000 # 当面付最大撤销次数和撤销间隔(毫秒) max_cancel_retry = 3 cancel_duration = 2000 # 交易保障线程第一次调度延迟和调度间隔(秒) heartbeat_delay = 5 heartbeat_duration = 900 复制代码
配置回调 url
两次回调,扫码进行一次回调,扫码付款成功进行一次回调
生成二维码,上传到 ftp
服务器
OrderServiceImpl.java
package com.mmall.service.impl; /** * Created by geely */ @Service("iOrderService") public class OrderServiceImpl implements IOrderService { private static AlipayTradeService tradeService; static { /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数 * Configs会读取classpath下的zfbinfo.properties文件配置信息,如果找不到该文件则确认该文件是否在classpath目录 */ Configs.init("zfbinfo.properties"); /** 使用Configs提供的默认参数 * AlipayTradeService可以使用单例或者为静态成员对象,不需要反复new */ tradeService = new AlipayTradeServiceImpl.ClientBuilder().build(); } private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class); @Autowired private OrderMapper orderMapper; @Autowired private OrderItemMapper orderItemMapper; @Autowired private PayInfoMapper payInfoMapper; @Autowired private CartMapper cartMapper; @Autowired private ProductMapper productMapper; @Autowired private ShippingMapper shippingMapper; public ServerResponse pay(Long orderNo,Integer userId,String path){ Map<String ,String> resultMap = Maps.newHashMap(); Order order = orderMapper.selectByUserIdAndOrderNo(userId,orderNo); if(order == null){ return ServerResponse.createByErrorMessage("用户没有该订单"); } resultMap.put("orderNo",String.valueOf(order.getOrderNo())); // (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、数字、下划线, // 需保证商户系统端不能重复,建议通过数据库sequence生成, String outTradeNo = order.getOrderNo().toString(); // (必填) 订单标题,粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费” String subject = new StringBuilder().append("happymmall扫码支付,订单号:").append(outTradeNo).toString(); // (必填) 订单总金额,单位为元,不能超过1亿元 // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】 String totalAmount = order.getPayment().toString(); // (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段 // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】 String undiscountableAmount = "0"; // 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号) // 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID String sellerId = ""; // 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元" String body = new StringBuilder().append("订单").append(outTradeNo).append("购买商品共").append(totalAmount).append("元").toString(); // 商户操作员编号,添加此参数可以为商户操作员做销售统计 String operatorId = "test_operator_id"; // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持 String storeId = "test_store_id"; // 业务扩展参数,目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法),详情请咨询支付宝技术支持 ExtendParams extendParams = new ExtendParams(); extendParams.setSysServiceProviderId("2088100200300400500"); // 支付超时,定义为120分钟 String timeoutExpress = "120m"; // 商品明细列表,需填写购买商品详细信息, List<GoodsDetail> goodsDetailList = new ArrayList<GoodsDetail>(); List<OrderItem> orderItemList = orderItemMapper.getByOrderNoUserId(orderNo,userId); for(OrderItem orderItem : orderItemList){ GoodsDetail goods = GoodsDetail.newInstance(orderItem.getProductId().toString(), orderItem.getProductName(), BigDecimalUtil.mul(orderItem.getCurrentUnitPrice().doubleValue(),new Double(100).doubleValue()).longValue(), orderItem.getQuantity()); goodsDetailList.add(goods); } // 创建扫码支付请求builder,设置请求参数 AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder() .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo) .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body) .setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams) .setTimeoutExpress(timeoutExpress) .setNotifyUrl(PropertiesUtil.getProperty("alipay.callback.url"))//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置 .setGoodsDetailList(goodsDetailList); AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder); switch (result.getTradeStatus()) { case SUCCESS: logger.info("支付宝预下单成功: )"); AlipayTradePrecreateResponse response = result.getResponse(); dumpResponse(response); File folder = new File(path); if(!folder.exists()){ folder.setWritable(true); folder.mkdirs(); } // 需要修改为运行机器上的路径 //细节细节细节 String qrPath = String.format(path+"/qr-%s.png",response.getOutTradeNo()); String qrFileName = String.format("qr-%s.png",response.getOutTradeNo()); ZxingUtils.getQRCodeImge(response.getQrCode(), 256, qrPath); File targetFile = new File(path,qrFileName); try { FTPUtil.uploadFile(Lists.newArrayList(targetFile)); } catch (IOException e) { logger.error("上传二维码异常",e); } logger.info("qrPath:" + qrPath); String qrUrl = PropertiesUtil.getProperty("ftp.server.http.prefix")+targetFile.getName(); resultMap.put("qrUrl",qrUrl); return ServerResponse.createBySuccess(resultMap); case FAILED: logger.error("支付宝预下单失败!!!"); return ServerResponse.createByErrorMessage("支付宝预下单失败!!!"); case UNKNOWN: logger.error("系统异常,预下单状态未知!!!"); return ServerResponse.createByErrorMessage("系统异常,预下单状态未知!!!"); default: logger.error("不支持的交易状态,交易返回异常!!!"); return ServerResponse.createByErrorMessage("不支持的交易状态,交易返回异常!!!"); } } // 简单打印应答 private void dumpResponse(AlipayResponse response) { if (response != null) { logger.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg())); if (StringUtils.isNotEmpty(response.getSubCode())) { logger.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(), response.getSubMsg())); } logger.info("body:" + response.getBody()); } } public ServerResponse aliCallback(Map<String,String> params){ Long orderNo = Long.parseLong(params.get("out_trade_no")); String tradeNo = params.get("trade_no"); String tradeStatus = params.get("trade_status"); Order order = orderMapper.selectByOrderNo(orderNo); if(order == null){ return ServerResponse.createByErrorMessage("非快乐慕商城的订单,回调忽略"); } if(order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){ return ServerResponse.createBySuccess("支付宝重复调用"); } if(Const.AlipayCallback.TRADE_STATUS_TRADE_SUCCESS.equals(tradeStatus)){ order.setPaymentTime(DateTimeUtil.strToDate(params.get("gmt_payment"))); order.setStatus(Const.OrderStatusEnum.PAID.getCode()); orderMapper.updateByPrimaryKeySelective(order); } PayInfo payInfo = new PayInfo(); payInfo.setUserId(order.getUserId()); payInfo.setOrderNo(order.getOrderNo()); payInfo.setPayPlatform(Const.PayPlatformEnum.ALIPAY.getCode()); payInfo.setPlatformNumber(tradeNo); payInfo.setPlatformStatus(tradeStatus); payInfoMapper.insert(payInfo); return ServerResponse.createBySuccess(); } public ServerResponse queryOrderPayStatus(Integer userId,Long orderNo){ Order order = orderMapper.selectByUserIdAndOrderNo(userId,orderNo); if(order == null){ return ServerResponse.createByErrorMessage("用户没有该订单"); } if(order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){ return ServerResponse.createBySuccess(); } return ServerResponse.createByError(); } } 复制代码
NATAPP1分钟快速新手图文教程
本文由博客一文多发平台 OpenWrite 发布!