Data table structure design
unique index ensures data uniqueness
CREATE TABLE `mmall_user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'User table id', `username` varchar(50) NOT NULL COMMENT 'User name', `password` varchar(50) NOT NULL COMMENT 'User password, MD5 encryption', `email` varchar(50) DEFAULT NULL, `phone` varchar(20) DEFAULT NULL, `question` varchar(100) DEFAULT NULL COMMENT 'Password recovery problem', `answer` varchar(100) DEFAULT NULL COMMENT 'Get back the password', `role` int(4) NOT NULL COMMENT 'Role 0-Administrators,1-Ordinary users', `create_time` datetime NOT NULL COMMENT 'Creation time', `update_time` datetime NOT NULL COMMENT 'Last update time', PRIMARY KEY (`id`), UNIQUE KEY `user_name_unique` (`username`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;
Single index and combined index
CREATE TABLE `mmall_order_item` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Booking form id', `user_id` int(11) DEFAULT NULL, `order_no` bigint(20) DEFAULT NULL, `product_id` int(11) DEFAULT NULL COMMENT 'commodity id', `product_name` varchar(100) DEFAULT NULL COMMENT 'Trade name', `product_image` varchar(500) DEFAULT NULL COMMENT 'Product image address', `current_unit_price` decimal(20,2) DEFAULT NULL COMMENT 'Unit price of goods when generating order, unit: Yuan,Keep two decimal places', `quantity` int(10) DEFAULT NULL COMMENT 'Quantity of commodities', `total_price` decimal(20,2) DEFAULT NULL COMMENT 'Total commodity price,The unit is yuan.,Keep two decimal places', `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;
Regret medicine for business problems
Create "time Update time
mybatis three swordsmen
Automatic generation of database interaction code by mybatis generator
Configure 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://Your database IP: your database Port / your 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> <!--Import property configuration--> <properties resource="datasource.properties"></properties> <!--Specify the jdbc drive jar Location of packages--> <classPathEntry location="${db.driverLocation}"/> <context id="default" targetRuntime="MyBatis3"> <!-- optional,Aimed at creating class Control comments when --> <commentGenerator> <property name="suppressDate" value="true"/> <property name="suppressAllComments" value="true"/> </commentGenerator> <!--jdbc Database connection for --> <jdbcConnection driverClass="${db.driverClassName}" connectionURL="${db.url}" userId="${db.username}" password="${db.password}"> </jdbcConnection> <!-- Not required, type processor, in database type and java Conversion control between types--> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- Model Model builder,Used to generate a primary key key Class, record class and query of Example class targetPackage Specify generated model Package name where the build is located targetProject Specify the path under the project --> <!--<javaModelGenerator targetPackage="com.mmall.pojo" targetProject=".\src\main\java">--> <javaModelGenerator targetPackage="com.mmall.pojo" targetProject="./src/main/java"> <!-- Whether subpackages are allowed, i.e targetPackage.schemaName.tableName --> <property name="enableSubPackages" value="false"/> <!-- Is it right? model Add constructor --> <property name="constructorBased" value="true"/> <!-- Are classes right? CHAR Type of column trim operation --> <property name="trimStrings" value="true"/> <!-- Established Model Whether the object is immutable or not Model Object will not have setter Method, only construction method --> <property name="immutable" value="false"/> </javaModelGenerator> <!--mapper The directory where the mapping file is generated generates the corresponding SqlMap file --> <!--<sqlMapGenerator targetPackage="mappers" targetProject=".\src\main\resources">--> <sqlMapGenerator targetPackage="mappers" targetProject="./src/main/resources"> <property name="enableSubPackages" value="false"/> </sqlMapGenerator> <!-- Client code, easy to use for Model Object and XML Code for profile type="ANNOTATEDMAPPER",generate Java Model And annotation based Mapper object type="MIXEDMAPPER",Generate annotation based Java Model And corresponding Mapper object type="XMLMAPPER",generate SQLMap XML Documentation and independent Mapper Interface --> <!-- targetPackage: mapper Interface dao Generated location --> <!--<javaClientGenerator type="XMLMAPPER" targetPackage="com.mmall.dao" targetProject=".\src\main\java">--> <javaClientGenerator type="XMLMAPPER" targetPackage="com.mmall.dao" targetProject="./src/main/java"> <!-- enableSubPackages:Whether to let schema As suffix of package --> <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 Building plug-ins --> </context> </generatorConfiguration>
Function
Mybatis plugin idea plug-in to realize the automatic jump of interface files and xml of mybatis
Mybatis PageHelper mybatis paging component
Configure 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>
Tomcat loads spring and springmvc
Mode 1: configure 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> <!-- Start our own listener --> <listener> <listener-class>com.atguigu.scw.manager.listener.MyAppListener</listener-class> </listener> <!-- start-up spring container --> <!-- 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> <!-- Add character encoding filter --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!-- Only the encoding format is specified --> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <!-- Solve the request garbled --> <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>
Mode 2: configure 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>
Test plug-in
User module
lateral ultra vires
Input parameter needs to specify current user id
Vertical ultra vires
MD5 clear text encryption
Salt value encryption
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]; } /** * Return to uppercase 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
Read the configuration file in the src/main/resources directory
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("Configuration file read exception",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=Your FTP The server ip address 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.,
Application: clear text encryption
guava cache
Set token and pass it to foreground user
Verify 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 algorithm private static LoadingCache<String,String> localCache = CacheBuilder.newBuilder().initialCapacity(1000).maximumSize(10000).expireAfterAccess(12, TimeUnit.HOURS) .build(new CacheLoader<String, String>() { //The default data loading implementation, when calling get value, if the key has no corresponding value, call this method to load @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){ //Explain that the question and answer are the user's and correct String forgetToken = UUID.randomUUID().toString(); TokenCache.setKey(TokenCache.TOKEN_PREFIX+username,forgetToken); return ServerResponse.createBySuccess(forgetToken); } return ServerResponse.createByErrorMessage("Wrong answer to the question"); } public ServerResponse<String> forgetResetPassword(String username,String passwordNew,String forgetToken){ if(org.apache.commons.lang3.StringUtils.isBlank(forgetToken)){ return ServerResponse.createByErrorMessage("Parameter error,token Need to pass"); } ServerResponse validResponse = this.checkValid(username,Const.USERNAME); if(validResponse.isSuccess()){ //user does not exist return ServerResponse.createByErrorMessage("user does not exist"); } String token = TokenCache.getKey(TokenCache.TOKEN_PREFIX+username); if(org.apache.commons.lang3.StringUtils.isBlank(token)){ return ServerResponse.createByErrorMessage("token Invalid or expired"); } 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("Password changed successfully"); } }else{ return ServerResponse.createByErrorMessage("token error,Please get the reset password again token"); } return ServerResponse.createByErrorMessage("Failed to modify password"); }
Design idea and encapsulation of high reuse service response object
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) //When serializing json, if it is a null object, the key will disappear 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 //Make it out of the json serialization results 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; } }
Classification module
recursive algorithm
/** * Recursively query the id of this node and the id of the child node * @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); } //Recursive algorithm, calculating the child nodes private Set<Category> findChildCategory(Set<Category> categorySet ,Integer categoryId){ Category category = categoryMapper.selectByPrimaryKey(categoryId); if(category != null){ categorySet.add(category); } //To find a child node, the recursive algorithm must have an exit condition List<Category> categoryList = categoryMapper.selectCategoryChildrenByParentId(categoryId); for(Category categoryItem : categoryList){ findChildCategory(categorySet,categoryItem.getId()); } return categorySet; }
Complex object weight removal
Set set
Override the equals and hashCode methods of the custom object Category
Infinite hierarchical tree structure design
Commodity module
POJO, BO, VO abstract model
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; } }
Static code block > normal code block > construct code block
Tomcat starts loading static code blocks
Time conversion tool class 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")); } }
Mybatis PageHelper efficient paging
Configure pom.xml
Realization
Mybatis PageHelper dynamic sorting
Implementation of List traversal by mybatis
mybatis dynamically assembles where statements
FTP service connection
Upload file to local first
Configure 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>
Configure dispatcher-servlet.xml
<!-- File upload --> <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(); //Extension name //abc.jpg String fileExtensionName = fileName.substring(fileName.lastIndexOf(".")+1); String uploadFileName = UUID.randomUUID().toString()+"."+fileExtensionName; logger.info("Start file upload,File name of the uploaded file:{},Upload path:{},New file name:{}",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); //The file has been uploaded successfully FTPUtil.uploadFile(Lists.newArrayList(targetFile)); //Uploaded to ftp server targetFile.delete(); } catch (IOException e) { logger.error("Upload file exception",e); return null; } //A:abc.jpg //B:abc.jpg return targetFile.getName(); } }
Connect to remote ftp and upload files
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("Start connecting ftp The server"); boolean result = ftpUtil.uploadFile("img",fileList); logger.info("Start connecting ftp The server,End uploading,Upload results:{}"); return result; } private boolean uploadFile(String remotePath,List<File> fileList) throws IOException { boolean uploaded = true; FileInputStream fis = null; //Connect to FTP server 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("Upload file exception",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("Connect FTP Server exception",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; } }
Rich text upload
Similar to ftp file upload, but with special requirements for return value
Shopping Cart module
Product total price calculation reuse package
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);//Round to 2 decimal places //An inexhaustible situation } }
High reuse logical method encapsulation idea
Solving the problem of losing precision in commercial operation
Be sure to use the String constructor of BigDecimal
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)); } }
Order module
Security vulnerability solution
Order number generation rules
Powerful constant and enumeration design
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;//Shopping cart selection status int UN_CHECKED = 0;//Not selected in cart String LIMIT_NUM_FAIL = "LIMIT_NUM_FAIL"; String LIMIT_NUM_SUCCESS = "LIMIT_NUM_SUCCESS"; } public interface Role{ int ROLE_CUSTOMER = 0; //Ordinary users int ROLE_ADMIN = 1;//Administrators } public enum ProductStatusEnum{ ON_SALE(1,"On-line"); 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,"Cancelled"), NO_PAY(10,"Unpaid"), PAID(20,"Paid"), SHIPPED(40,"Shipped"), ORDER_SUCCESS(50,"Order fulfillment"), ORDER_CLOSE(60,"Order closure"); 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("No corresponding enumeration found"); } } 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,"Alipay"); 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,"Online payment"); 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("No corresponding enumeration found"); } } }
Use
mybatis bulk insert
Receiving address
Get auto increment primary key synchronously
Object binding of data binding
Ship to address object must have get and set methods
Strengthening the problem of exceeding authority
Payment module
Alipay SDK source analysis
Download and use of server SDK
Alipay payment process and integration
Import dependency
To configure the maven plug-in, in addition to the dependency of pom.xml configuration, the dependency in the lib package will also be packaged and deployed together
Configure the sandbox environment zfbinfo.properties
# Alipay gateway name, partnerId and 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, public key and Alipay public key 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 corresponds to Alipay public key #alipay_public_key = MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDI6d306Q8fIfCOaTXyiUeJHkrIvYISRcc73s3vF1ZT7XN8RNPwJxo8pWaJMmvyTn9N4HQ632qJBVHf8sxHi/fEsraprwCtzvzQETrNRwVxLO5jVmRGi60j8Ue1efIlzPXV9je9mkjzOmdssymZkh2QhUrCmZYI/FCEa3/cNMW0QIDAQAB #SHA256withRsa corresponds to Alipay public key alipay_public_key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqzWgVL/NWrJAeyEImwtaK3IDwj0dKkqUDIfqqWn5SiLaWMYi9RmKhn+jY9VM7JXEIkYYeVlqIL6Xn7OvYFRTi4buTCXGKvFLn95aDcaur77/S/0ibcdN1K2wIoHzaqQhXAb1ezKxTnFP7OLJsAL22b0NzrQDj2OH9SA06gJb8nHBfR+7Sx7DfwcqE0OtTcDHjbbcB24Qgg/dfItxoEnKuSyRVrf6BtpUnJxSzG/Ge7FfF+VBq8re1t4ZTSxaDEjto071I5VFBxr7I4SyqZsc7WpAmZL8AqUgEbQ1XYBWx2LnpJXM5GQW/thUvcDDqzea7LJNWJOQPM5DaZQgu7QuuwIDAQAB # Signature type: RSA - > sha1withrsa, RSA2 - > sha256withrsa sign_type = RSA2 # Maximum number of face-to-face queries and query interval (MS) max_query_retry = 5 query_duration = 5000 # Maximum cancellation times and interval of face-to-face payment (MS) max_cancel_retry = 3 cancel_duration = 2000 # First scheduling delay and scheduling interval of transaction support thread (seconds) heartbeat_delay = 5 heartbeat_duration = 900
QR code generation, code scanning payment
Configure callback url
Two callbacks, one for code scanning, and one for code scanning payment
Generate QR code and upload it to ftp server
OrderServiceImpl.java
package com.mmall.service.impl; /** * Created by geely */ @Service("iOrderService") public class OrderServiceImpl implements IOrderService { private static AlipayTradeService tradeService; static { /** Be sure to call Configs.init() to set default parameters before creating AlipayTradeService. * Configs The configuration information of zfbinfo.properties file under classpath will be read. If the file cannot be found, confirm whether the file is in classpath directory */ Configs.init("zfbinfo.properties"); /** Use the default parameters provided by Configs * AlipayTradeService You can use singleton or static member objects without repeating 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("User does not have the order"); } resultMap.put("orderNo",String.valueOf(order.getOrderNo())); // (required) the unique order number in the order system of the merchant website, within 64 characters, can only contain letters, numbers and underscores, // It is necessary to ensure that the system end of the merchant cannot be duplicated. It is recommended to generate it through the database sequence, String outTradeNo = order.getOrderNo().toString(); // (required) Order title, which roughly describes the user's payment purpose. For example, "xxx brand xxx store pay and scan code consumption face to face" String subject = new StringBuilder().append("happymmall Sweep code payment,Order number:").append(outTradeNo).toString(); // (required) total order amount, unit: yuan, no more than 100 million yuan // If the discount amount, non discount amount and total order amount are passed in at the same time, the following conditions must be met: total order amount = [discount amount] + [non discount amount] String totalAmount = order.getPayment().toString(); // (optional) the order cannot be discounted. You can configure the discount activity with the merchant platform. If the beverage does not participate in the discount, fill in the corresponding amount in this field // If the value is not passed in, but the total order amount and discount amount are passed in, the default value is total order amount - discount amount String undiscountableAmount = "0"; // The seller's Alipay account ID is used to support a signed account to support the payment to different account receipts, (to sellerId corresponding Alipay account). // If the field is empty, the default is the PID of the merchant contracted with Alipay, that is, the PID corresponding to appid. String sellerId = ""; // For order description, you can give a detailed description of the transaction or commodity, for example, fill in "purchase 2 items of 15.00 yuan in total" String body = new StringBuilder().append("Order").append(outTradeNo).append("Purchase of goods").append(totalAmount).append("element").toString(); // Merchant operator number. Add this parameter to make sales statistics for the merchant operator String operatorId = "test_operator_id"; // (required) merchant shop number, through the store number and business backstage can be configured to store discount information accurately, detailed inquiry Alipay technical support String storeId = "test_store_id"; // The business expansion parameters can be added to the system vendor number assigned by Alipay (through the setSysServiceProviderId method). For details, please consult Alipay technical support. ExtendParams extendParams = new ExtendParams(); extendParams.setSysServiceProviderId("2088100200300400500"); // Payment timeout, defined as 120 minutes String timeoutExpress = "120m"; // Detailed list of goods, details of purchased goods shall be filled in, 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); } // Create scan payment request builder and set request parameters 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"))//Alipay server initiatively tells the http path specified in the merchant server, which is set up according to need. .setGoodsDetailList(goodsDetailList); AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder); switch (result.getTradeStatus()) { case SUCCESS: logger.info("Alipay orders successfully: )"); AlipayTradePrecreateResponse response = result.getResponse(); dumpResponse(response); File folder = new File(path); if(!folder.exists()){ folder.setWritable(true); folder.mkdirs(); } // Need to change to run path on machine //Details details 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("Upload QR code exception",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("Alipay pre order failure!!!"); return ServerResponse.createByErrorMessage("Alipay pre order failure!!!"); case UNKNOWN: logger.error("System exception, pre order status unknown!!!"); return ServerResponse.createByErrorMessage("System exception, pre order status unknown!!!"); default: logger.error("Unsupported transaction status, transaction returned exception!!!"); return ServerResponse.createByErrorMessage("Unsupported transaction status, transaction returned exception!!!"); } } // Simple print response 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("Orders from non happy mall,Callback ignored"); } if(order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){ return ServerResponse.createBySuccess("Alipay repeated calls"); } 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("User does not have the order"); } if(order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){ return ServerResponse.createBySuccess(); } return ServerResponse.createByError(); } }
Intranet penetration
NATAPP1 minute fast novice graphic tutorial
Online deployment
ECS vsftpd, nginx and other configurations
ECS configuration and domain name resolution
Notes on launching
This article is based on the platform of blog one article multiple sending OpenWrite Release!