商业软件项目搭建指南(SpringMVC篇)——第八章:项目业务代码开发

本章详细介绍如何开发的我们项目业务代码。首先介绍Maven的pom文件里详细内容;然后开发项目框架代码;最后按照后台管理、会员中心和前端展现三个部分开发对应的代码。

目录

第1节、编辑Maven pom文件

第2节、开发项目框架代码

2.1、开发项目运行入口类WfsmwApplication

2.2、开发项目以war包方式运行入口类ServletInitializer

2.3、开发项目配置Spring MVC行为的配装器类WfsmwWebMvcConfigurer

第3节、后台管理

3.1、开发管理员登录功能及其页面

3.2、开发管理员管理功能及其页面

3.3、开发会员管理功能及其页面

3.4、开发商品模块功能及其页面

3.5、开发订单模块功能及其页面

3.6、开发模块数据管理功能及其页面

第4节、会员中心

4.1、开发会员注册功能及其页面

3.2、开发会员登录功能及其页面

4.3、开发我的订单功能及其页面

4.4、开发个人信息功能及其页面

4.5、开发收货地址功能及其页面

4.6、开发修改密码功能及其页面

第5节、前端展现

5.1、开发网站首页页面

5.2、开发商品模块前端页面

5.3、开发模块数据列表页面

5.4、开发购物车页面

5.5、开发确认订单页面

5.6、开发选择支付方式页面

5.7、开发提交订单页面

5.8、开发获取支付结果页面

5.9、开发支付宝支付功能

5.10、开发微信支付功能


第1节、编辑Maven pom文件

本小节是对Maven管理项目配置文件pom.xml进行编辑和详细说明,具体请查看如下。

  

    4.0.0

    

    

        org.springframework.boot

        spring-boot-starter-parent

        2.7.11

        

    

    

    cn.sanqingniao

    

    wfsmw

    

    0.0.1-SNAPSHOT

    

    war

    

    wfsmw

    

    Worry-Free Shopping Mall Website

    

    

        

        1.8

    

    

    

        

        

            org.springframework.boot

            spring-boot-starter-web

            

                

                

                    org.springframework.boot

                    spring-boot-starter-logging

                

            

        

        

        

            org.mybatis.spring.boot

            mybatis-spring-boot-starter

            2.2.2

        

        

        

            com.mysql

            mysql-connector-j

            runtime

        

        

        

            com.alibaba

            druid-spring-boot-starter

            1.2.16

        

        

        

            org.springframework.boot

            spring-boot-starter-thymeleaf

        

        

        

            org.springframework.boot

            spring-boot-starter-test

            test

        

        

        

            org.springframework.boot

            spring-boot-starter-tomcat

            provided

        

        

        

            org.springframework.boot

            spring-boot-starter-log4j

            1.3.8.RELEASE

        

        

        

            org.springframework.boot

            spring-boot-starter-data-redis

        

        

        

            org.springframework.boot

            spring-boot-devtools

            runtime

            true

        

        

        

            org.springframework.data

            spring-data-mongodb

        

        

        

            joda-time

            joda-time

            2.12.2

        

        

        

            com.google.zxing

            core

            2.2

        

        

        

            com.alibaba

            fastjson

            1.2.40

        

        

        

            org.bouncycastle

            bcprov-jdk15on

            1.70

        

        

        

            org.apache.commons

            commons-lang3

            3.12.0

        

        

        

            commons-io

            commons-io

            2.11.0

        

        

        

            commons-collections

            commons-collections

            3.2.2

        

        

        

            commons-codec

            commons-codec

            1.15

        

        

        

            commons-digester

            commons-digester

            2.1

        

        

        

            org.jdom

            jdom

            2.0.2

        

        

        

            org.jsoup

            jsoup

            1.15.4

        

        

        

            com.alipay.sdk

            alipay-sdk-java

            4.35.79.ALL

        

        

        

            com.qiniu

            qiniu-java-sdk

            7.13.0

        

        

            com.qiniu

            happy-dns-java

            0.1.6

            test

        

        

        

            com.squareup.okhttp3

            okhttp

            4.10.0

            compile

        

        

        

            org.apache.httpcomponents

            httpclient

            4.5.14

        

    

上述这些在pom.xml文件中的Maven配置代码,主要声明、定义了本项目一些属性和所有使用到第三方开源软件包,还有一些关于Maven插件的配置代码,请到本项目的源代码里去查看,在这里就不再赘述了。

第2节、开发项目框架代码

本小节是对项目Java框架代码的功能进行开发和详细说明。

2.1、开发项目运行入口类WfsmwApplication

根据Spring Boot框架,项目必须要有一个程序运行入口类,其类名通常是项目名+ Application。我们项目名叫wfsmw,所以该类名为WfsmwApplication,其主体代码如下:

1行  @SpringBootApplication

2行  @ServletComponentScan(basePackages = "cn.sanqingniao")

3行  @ComponentScan(basePackages = "cn.sanqingniao")

4行  @MapperScan(basePackages = "cn.sanqingniao.wfsmw.dao")

5行  public class WfsmwApplication {

6行      public static void main(String[] args) {

7行          SpringApplication.run(WfsmwApplication.class, args);

8行      }

9行  }

在这些代码里,每行代码的意义说明如下:

第1行代码@SpringBootApplication,它是一个注解,意思是表明当前类是一个Spring Boot程序入口。

第2行代码@ServletComponentScan(basePackages = "cn.sanqingniao"),它是一个注解,意思是表明告知Spring Bean容器要以cn.sanqingniao包为基础包,开始去扫描、加载它及其所有子包里的所有Servlet、Filter和Listener组件。

第3行代码@ComponentScan(basePackages = "cn.sanqingniao"),它是一个注解,意思是表明告知Spring Bean容器要以cn.sanqingniao包为基础包,开始去扫描、加载它及其所有子包里的所有带有@Component注解的组件。

第4行代码@MapperScan(basePackages = "cn.sanqingniao.wfsmw.dao"),它是一个注解,意思是表明告知Spring Bean容器要以cn.sanqingniao.wfsmw.dao包为基础包,开始去扫描、加载它及其所有子包里的持久层的所有数据访问对象组件及其SQL脚本映射文件。

第5至9行代码,就是定义了WfsmwApplication 这个类,并且在该类定义了我们项目程序运行入口main方法,在该方法里只有第7行一行代码,它的意思是指执行项目程序。

2.2、开发项目以war包方式运行入口类ServletInitializer

当你希望项目以war包方式部署到Web容器中(如Tomcat、Jetty等服务器)运行时,根据Spring Boot框架,项目必须要有一个实现SpringBootServletInitializer入口类。在本项目里该类为ServletInitializer,其主体代码如下:

1行  public class ServletInitializer extends SpringBootServletInitializer {

2行     @Override

3行     protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {

4行        return application.sources(WfsmwApplication.class);

5行     }

6行  }

该类非常简单,就是直接继承SpringBootServletInitializer父类;然后实现了configure方法,如第3行代码;在该方法了也非常简单,就是在Spring应用构建器里传入我们项目的主程序入口类WfsmwApplication的class对象。

2.2.1、Spring Boot项目以war包方式运行原理

在Spring Boot项目中,ServletInitializer类是用来启动Spring Boot应用程序的类。当应用程序被部署到Servlet容器中时,容器需要知道如何启动这个应用程序。在这种情况下,ServletInitializer类就会派上用场。

ServletInitializer类的主要作用是配置Spring Boot应用程序的上下文。当容器启动时,它会读取这个类,并执行其中的configure()方法来启动应用程序。在configure()方法中,我们需要使用SpringApplicationBuilder类来指定Spring Boot应用程序的主类。

在执行ServletInitializer类之前,我们需要将Spring Boot项目打包成war包。然后,在Servlet容器中部署war包后,容器会读取web.xml文件,并查找实现javax.servlet.ServletContainerInitializer接口的类。SpringBootServletInitializer是实现了这个接口的一个特殊的初始化器。

执行ServletInitializer类有两种方式:

1. 使用命令行方式运行:

使用如下命令可以直接运行打包好的war包:

java -jar ROOT.war

2. 在Web容器中部署:

将打包好的war包部署到Web容器中,如Tomcat、Jetty等,并启动Web容器。Web容器会自动查找web.xml文件,并执行其中配置好的初始化器。在这种情况下,初始化器就是SpringBootServletInitializer类,在其中调用configure()方法启动Spring Boot应用程序。

2.2.2、Spring Boot项目以war包方式运行配置

为了将Spring Boot应用程序打包成war包,并能够在Servlet容器中部署运行,需要进行以下配置:

1. 修改pom.xml文件

在pom.xml文件中,需要将打包方式改为war,并将spring-boot-starter-tomcat依赖修改为provided,它的意思是指在打包为war时不要把Spring Boot内置的Tomcat打包进去,如下所示:

war

    

    

        org.springframework.boot

        spring-boot-starter-tomcat

        provided

    

    

2. 创建ServletInitializer类

在Spring Boot应用程序中创建一个继承自SpringBootServletInitializer的ServletInitializer类,并重写configure方法,如下所示:

public class ServletInitializer extends SpringBootServletInitializer {

    @Override

    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {

        return application.sources(WfsmwApplication.class);

    }

}

其中,WfsmwApplication.class是Spring Boot应用程序的主类。

3. 配置启动类

在启动类上添加一个注解@ServletComponentScan,如下所示:

@SpringBootApplication

@ServletComponentScan

public class WfsmwApplication{

    public static void main(String[] args) {

        SpringApplication.run(WfsmwApplication.class, args);

    }

}

这个注解用于扫描所有的Servlet、Filter和Listener组件。

通过以上配置,就可以将Spring Boot应用程序打包成war包,并在Servlet容器中部署运行。

2.2.3、在IDEA里配置Tomcat及运行项目

首先、到Apache官网下载Tomcat9,之所以下载Tomcat9这个版本,是因为我们项目使用的Java版本是1.8,它只能支持Tomcat最高的版本就是9;其它更高版本的Tomcat,需要更高版本的Java。Tomcat9的Windows 64位版本下载地址如下:

https://downloads.apache.org/tomcat/tomcat-9/v9.0.74/bin/apache-tomcat-9.0.74-windows-x64.zip

如果你希望下载其它版本,请在https://downloads.apache.org/tomcat/tomcat-9/v9.0.74/bin/目录里查找。

然后、在IntelliJ IDEA开发软件里,选择“运行--->>编辑配置”菜单,如下图:

商业软件项目搭建指南(SpringMVC篇)——第八章:项目业务代码开发_第1张图片

点击这个菜单,打开“运行/调试配置”窗口,如下图:

商业软件项目搭建指南(SpringMVC篇)——第八章:项目业务代码开发_第2张图片

点击上图左上角标号1的 + 按钮,打开添加新配置菜单窗口,在该窗口里选择“Tomcat服务器”菜单里的本地子菜单,打开添加“Tomcat 服务器”配置窗口,如上图标号2;然后在上图标号3输入框里设置名称,如本项目名称叫“WFSMW服务器”;之后在上图标号4输入框里点击“配置”按钮,打开“应用程序服务器”窗口,在该窗口里设置你之前下载安装的Tomcat9的路径;之后在上图标号5输入框里选择JRE版本,如本项目选择1.8版本。

最后、部署项目war包,在上图标号4上一行,选择“部署”Tab框,得到如下图:

商业软件项目搭建指南(SpringMVC篇)——第八章:项目业务代码开发_第3张图片

点击上图标号1的“部署”Tab菜单,打开部署项目war包Tab框;点击上图标号2的 + 按钮,在弹出的菜单框里选择“工件”子菜单,打开“选择要部署的工件”窗口,在该窗口里选择项目war包,如本项目wfsmw:war包,即上图标号3;点击“确定”按钮之后,再得到如下图窗口。

商业软件项目搭建指南(SpringMVC篇)——第八章:项目业务代码开发_第4张图片

在上图红色框里,设置应用程序上下文,如本项目设置为“/”;最后,点击“确定”按钮,就是把所有部署配置添加好了;然后就可以在IDEA里正常启动Tomcat,运行项目程序了。

关于应用程序上下文的设置,在这里简单阐述一下。

如果你在该上下文里设置了“/wfsmw”,那么在你访问项目功能路径里,就要增加这个上下文。例如,你的后台管理登录功能页面URI是/admin/login.html,那么它的访问全路径URL是http://localhost:8080/wfsmw/admin/login.html。

例如,本项目在该上下文里设置了“/”,那么该登录功能页面的访问全路径URL是http://localhost:8080/admin/login.html。

2.3、开发项目配置Spring MVC行为的配装器类WfsmwWebMvcConfigurer

当你希望项目添加一些全局的过滤器、拦截器、异常处理器时,在Spring Boot项目中,通过实现WebMvcConfigurer这个接口来达到目录。

在Spring Boot项目中,WebMvcConfigurer是用来配置Spring MVC的类。它提供了一些方法,用于配置Spring MVC的行为,如拦截器、消息转换器、静态资源处理等。

WebMvcConfigurer的主要作用是提供一个回调函数,让我们可以自定义一些Spring MVC的配置。WebMvcConfigurer中定义了许多方法,我们可以通过覆盖这些方法来自定义Spring MVC的配置。例如,下面是一些常见的方法:

- addInterceptors():添加拦截器

- addViewControllers():添加视图控制器

- configureContentNegotiation():配置内容协商

- configureDefaultServletHandling():配置默认Servlet处理

- configureMessageConverters():配置消息转换器

- addResourceHandlers():添加静态资源处理器

- configureHandlerExceptionResolvers:配置处理异常解析器

执行WebMvcConfigurer有两种方式:

1. 通过@EnableWebMvc注解标注类

如果我们需要自定义Spring MVC的配置,可以在一个类上标注@EnableWebMvc注解,并实现WebMvcConfigurer接口。在这种情况下,所有WebMvcConfigurer中定义的方法都会被执行。例如:

@Configuration

@EnableWebMvc

public class MyConfig implements WebMvcConfigurer {

    // 在这里覆盖需要自定义的方法

}

2. 继承WebMvcConfigurationSupport类

我们也可以通过继承WebMvcConfigurationSupport类来实现自定义Spring MVC的配置。在这种情况下,我们需要覆盖configureXXX()方法来实现自定义逻辑。例如:

@Configuration

public class MyConfig extends WebMvcConfigurationSupport {

    // 在这里覆盖需要自定义的方法

}

需要注意的是,如果我们使用继承WebMvcConfigurationSupport类来自定义Spring MVC的配置,那么Spring Boot的自动配置将失效。因此,我们需要自己手动配置很多东西,包括视图解析器、消息转换器、异常处理等。

如果我们只需要自定义一些简单的配置,例如添加拦截器、处理静态资源等,那么建议使用@EnableWebMvc注解来实现。如果我们需要完全掌控Spring MVC的配置,那么建议继承WebMvcConfigurationSupport类来实现。

总之,WebMvcConfigurer是用来配置Spring MVC的类,在Spring Boot项目中非常有用。我们可以通过它来实现自定义拦截器、消息转换器、静态资源处理等功能。

在我们项目里,通过在WfsmwWebMvcConfigurer这个类上标注@EnableWebMvc注解,并实现WebMvcConfigurer接口,来实现添加一些全局的拦截器和异常处理器,具体代码如下:

1行  @Configuration

2行  @EnableWebMvc

3行  public class WfsmwWebMvcConfigurer implements WebMvcConfigurer {

4行      @Autowired

5行      private UserLoginInterceptor userLoginInterceptor;

6行      @Autowired

7行      private GlobalExceptionResolver globalExceptionResolver;

8行      @Override

9行      public void addInterceptors(InterceptorRegistry registry) {

10行          registry.addInterceptor(userLoginInterceptor)

11行                  .addPathPatterns("/admin/*/**", "/member/*/**")

12行                  .excludePathPatterns("/admin/", "/admin/login.html", "/admin/logout.html")

13行                  .excludePathPatterns("/member/", "/member/login.html", "/member/login-w.html", "/member/logout.html", "/member/register.html", "/member/register-w.html");

14行          WebMvcConfigurer.super.addInterceptors(registry);

15行      }

16行      @Override

17行      public void configureHandlerExceptionResolvers(List resolvers){

18行          resolvers.add(globalExceptionResolver);

19行          WebMvcConfigurer.super.configureHandlerExceptionResolvers(resolvers);

20行      }

21行  }

在第1、2行代码里的@Configuration和@EnableWebMvc这两个注解,表明该类是一个配置且能够控制Spring MVC行为的类。第5行代码是定义了一个用户登录时拦截器,该拦截器主要目的是检查访问后台管理和会员中心时,用户是否登录?如果没有登录就跳转到登录页面。第7行代码是定义一个处理全局异常解析器,在后台程序运行时所有为被处理的异常,都由该解析器进行处理。第9至15代码,就是实现添加拦截器的方法,其中第10行代码意思是添加了用登录拦截器,第11行代码意思是添加访问URI路径模式,才会被拦截,例如本项目里后台管理的访问URI路径模式是"/admin/*/**",会员中心的访问URI路径模式"/member/*/**";第12、13行代码意思在访问后台管理和会员中心时一些路径不需要被拦截,例如一些登录、注册路径。第17至20行代码,就是实现配置处理异常解析器。

第3节、后台管理

本小节是对后台管理部分的功能进行开发和详细说明;根据第二章概述,后台管理部分含有管理员管理、会员管理、商品管理、订单管理和模块数据管理这些功能及其页面。

一般开发一个功能代码的思维逻辑顺序是从最底层数据库开始依次往上层开发到最上层前端页面,具体步骤顺序如下:

  1. 设计、查看数据库表结构,理解表里每个字段的意义,以及表与表之间的关系。
  2. 开发持久层和实体层代码,在本项目里对应代码文件就是相关模块的dao包里的Dao接口、Mybatis的SQL脚本映射xml文件和实体层的Entity类,这步可以使用MyBatis反向生成代理插件自动生成主体代码及其文件。然后根据实际业务需求,在Dao接口里添加方法和在映射xml文件里添加SQL脚本及其参数配置。
  3. 开发业务服务层代码,在本项目里对应代码文件就是相关模块的service包里的Service类,并且该类必须继承该层基类BaseService;在该类里根据实际业务需求,添加相关方法,对数据库里的数据进行增、改、删、查、转换、格式化等等业务操作;如果是对数据库里的数据进行增、改、删这三种操作,还需要在方法上增加数据库事务控制@Transactional注解。
  4. 开发控制层代码,在本项目里对应代码文件就是相关模块的controller包里的Controller类,并且该类必须继承该层基类WfsmwBaseController或者其模块里的基类,例如在本项目里后台管理模块就有自己的基类AdminBaseController,会员中心模块也有自己的基类AbstractMemberController,当然这两个基类都继承了项目基类WfsmwBaseController。在这些Controller类,根据实际业务需求,添加相关控制层方法。
  5. 开发视图层代码,所谓视图层代码就是前端页面模板文件;在本项目里对应代码文件就是在资源模板文件/resources/templates的相关模块的子目录里的html文件。一般来说,一个项目里所有前端页面,都有统一的总体风格和布局,因此这些风格和布局代码都是统一放在相关css文件里。

上述开发代码的过程顺序,不一定是固定不变的,因为在实际项目开发中,这些工作不是一个人来做的,是多个人分工合作的,因此有时是同时进行的。一般的分工为第1步会由产品经理、架构师和技术经理一起讨论完成的,第2至4步由一个后端软件开发师完成,第5步由UI设计师和前端软件开发师一起合作完成的。

3.1、开发管理员登录功能及其页面

本小节是对管理员登录的功能进行开发和详细说明;登录功能可分为登录页面和登录认证这两个小功能点。

3.1.1、开发管理员登录页面

根据项目架构规划,该登录页面属于管理员模块,它的控制器及其页面开发说明如下:

第1步、在控制层的cn.sanqingniao.wfsmw.controller.admin子控制器包里,增加LoginController控制器类,它继承了AdminBaseController这个后台管理部分的基类,在该类里增加login控制方法,它的主体代码如下:

1行  @Controller

2行  @CrossOrigin

3行  public class LoginController extends AdminBaseController {

4行      @GetMapping(value = "login.html")

5行      public String login(ModelMap modelMap) throws Exception {

6行          initPageData(modelMap);

7行          return "admin/login";

8行      }

9行  }

第1行代码是@Controller注解,它表明LoginController是一个控制层的组件。

第2行代码是@CrossOrigin注解,它表明该控制器类是可以夸域访问的。

第4行代码是@GetMapping(value = "login.html")注解,它表明当前登录方法是以Get方式访问,并且设置它的访问路径是login.html,因为它是属于管理员模块的,因此它的全路径访问是:/admin/login.html。

第6行代码是调用基类WfsmwBaseController的initPageData方法,由于在登录页面需要对登录密码进行加密,在该方法里是初始化加密需要的密钥信息到登录页面里。

第7行代码是返回视图层的"admin/login"视图,其中“admin”是在视图层模板目录的管理员模块admin子目录里,“login”是视图文件名,把文件名后缀“.html”不要加上,Spring MVC架构在定位视图文件时自动加上。

第2步、根据前端页面总体风格,开发出login.html这个前端静态HTML页面,根据项目架构规划,该登录页面属于管理员模块,因此它存放路径为:/resources/templates/admin/login.html。该视图模板文件的全部源代码,请到本项目代码库里去查看。

3.1.2、开发管理员登录认证功能

第1步、根据第六章数据库表结构设计,管理员信息对应的数据库表是t_user,且用户类型是0:管理员和1:网站员工的数据。

第2步、登录功能的业务是根据登录用户名从数据库里获取用户信息,因此在持久层的UserDao接口里,添加一个getUserByName方法,代码如下:

UserEntity getUserByName(String userName);

然后在SQL脚本映射UserDao.xml文件里,添加一个

    select

    

    from t_user

    where user_name = #{userName,jdbcType=VARCHAR}

  

第3步、在业务服务层的cn.sanqingniao.wfsmw.service.user子服务包里,增加UserService服务类,它继承了BaseService这个业务服务层的基类,在该类里增加getUserByName业务方法,它的代码如下:

    public UserEntity getUserByName(String userName) {

        return userDao.getUserByName(userName);

    }

它主要就是一行调用Dao层的代码。

第4步、在控制层的cn.sanqingniao.wfsmw.controller.admin子控制器包的LoginController控制器类里,增加login控制方法,它的主体代码如下:

    @PostMapping(value = "login.html")

    public String login(String userName, String password, ModelMap modelMap, HttpServletRequest request, HttpServletResponse response) throws Exception {

  ......

    }

在这个方法里第1行代码@PostMapping(value = "login.html")是注解,表明当前登录方法是以Post方式访问,并且设置它的访问路径是login.html,因为它是属于管理员模块的,因此它的全路径访问是:/admin/login.html。在该方法的参数里,userName和password这两个参数就是从页面里传递过来的;该方法主要业务逻辑就是首先认证从页面上传递过来的两个参数是否为空,然后对登录密码进行解密;然后调用业务层第3步的getUserByName业务方法,获取登录用户信息;如果获取到了用户信息,那么之后就比较登录秘密是否与数据库里的一致;如果一致,则表示登录成功,那么处理登录成功之后业务信息,例如:为用户创建登录Token,把用户信息保存到Redis缓存和Session里,然后记录登录日志和操作日志信息。最后重定向到本项目的主页面里。该控制方法的全部源代码,请到本项目代码库里去查看。

3.2、开发管理员管理功能及其页面

本小节是对管理员管理的功能进行开发和详细说明;管理员管理主要有新增、修改、查询、启用和禁用功能点。

3.2.1、开发新增管理员功能及其页面

根据项目架构规划,该功能属于管理员模块,它的持久层Dao接口、SQL脚本映射xml文件、业务服务类、控制器及其页面开发说明如下:

第1步、设计和确认管理员信息对应的数据库表。根据第六章数据库表结构设计,管理员信息对应的数据库表是t_user,且用户类型是0:管理员和1:网站员工的数据。

第2步、在持久层的cn.sanqingniao.wfsmw.dao.user.UserDao接口里,新增功能的业务是把用户信息保存到数据库里,因此,添加一个insert方法,代码如下:

int insert(UserEntity record);

然后在SQL脚本映射UserDao.xml文件里,添加一个新增元素项及其新增SQL脚本,代码如下:

  

    insert into t_user (id, user_name, password,

                        user_type, status, portrait_uri,

                        cell_num, email, qq,

                        real_name, nickname, gender,

                        birthday, invite_code, card_number,

                        login_password, secret_key, register_time,

                        last_login_time, last_login_ip, create_time,

                        creator_id, last_modifier_id, last_modify_time)

    values (#{id,jdbcType=VARCHAR}, #{userName,jdbcType=VARCHAR}, {password,jdbcType=VARCHAR},

            #{userType,jdbcType=TINYINT}, #{status,jdbcType=TINYINT}, #{portraitUri,jdbcType=VARCHAR},#{cellNum,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, #{qq,jdbcType=VARCHAR},#{realName,jdbcType=VARCHAR}, #{nickname,jdbcType=VARCHAR}, #{gender,jdbcType=TINYINT}, #{birthday,jdbcType=DATE}, #{inviteCode,jdbcType=VARCHAR}, #{cardNumber,jdbcType=VARCHAR}, #{loginPassword,jdbcType=VARCHAR}, #{secretKey,jdbcType=VARCHAR}, #{registerTime,jdbcType=TIMESTAMP}, #{lastLoginTime,jdbcType=BIGINT}, #{lastLoginIp,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{creatorId,jdbcType=VARCHAR}, #{lastModifierId,jdbcType=VARCHAR}, #{lastModifyTime,jdbcType=BIGINT})

  

第3步、在业务服务层的cn.sanqingniao.wfsmw.service.user.UserService服务类,在该类里增加insert业务方法,它的代码如下:

    1行  @Transactional

    2行  public boolean insert(UserEntity user) {

    3行      user.setId(getNewUID());

    4行      // 为当前新用户生成邀请码。

    5行      String inviteCode = getLastInviteCode();

    6行      user.setInviteCode(inviteCode);

    7行      // 12位用户卡号在默认情况下使用邀请码,不足情况下左边补0

    8行      user.setCardNumber(leftPad(inviteCode, 12, '0'));

    9行      // 加密登录密码

    10行      encryptLoginPassword(user);

    11行      boolean result = userDao.insert(user) > 0;

    12行      if (result) {

    13行          // 新增用户登录日志信息

    14行          insertLoginLog(user);

    15行      }

    16行      return result;

    17行  }

第1行代码@Transactional是注解,它表明当前方法需要增加数据库事务控制。

第2至10行代码,分别是生成用户的ID、邀请码、卡号、加密登录密码。

第11行代码,调用持久层userDao的insert方法,把用户信息保存到数据库里。

第14行代码,新增用户登录日志信息。

第4步、在控制层的cn.sanqingniao.wfsmw.controller.admin子控制器包里,新增AdminManageController控制器类,它继承了AdminBaseController这个后台管理部分的基类,在该类里增加getAdmin和saveAdmin这两个控制方法,它们的主体代码如下:

@RequestMapping("get_admin.html")

public String getAdmin(String id, ModelMap modelMap) {

  ......

}

@RequestMapping("save_admin.html")

public String saveAdmin(UserEntity currentAdmin, ModelMap modelMap) {

  ......

}

在getAdmin这个方法里,是打开新增和编辑管理员页面,当参数用户id为空,表示打开新增页面;否则根据这个用户ID,调用业务服务层的方法获取用户信息,然后打开编辑页面。在saveAdmin这个方法里,是新增用户信息;在该方法里,首先检查参数currentAdmin对象里的一些必须值是否符合业务要求;然后调用业务服务层的UserService服务类的insert业务方法,来新增用户信息。

第5步、根据前端页面总体风格,开发出admin_edit.html这个前端静态HTML页面,根据项目架构规划,该管理员编辑页面属于管理员模块,因此它存放路径为:/resources/templates/admin/admin_edit.html。

对于管理员管理模块的修改、删除、查询、启用和禁用这些功能点,都是可以按照上述思路和顺序进行开发代码。

上述这些功能点的全部源代码,请到本项目代码库里去查看。

3.2.2、开发修改管理员功能及其页面

根据第3.2.1节开发思路和顺序,开发修改管理员功能点的持久层Dao接口、SQL脚本映射xml文件、业务服务类、控制器及其页面,具体过程就不再阐述;对于修改功能点,它在每个层级对应的类及其方法说明如下:

  1. 在持久层的cn.sanqingniao.wfsmw.dao.user.UserDao接口里的updateByPrimaryKeySelective方法,及其SQL脚本映射UserDao.xml文件的这个更新元素项。
  2. 在业务服务层的cn.sanqingniao.wfsmw.service.user.UserService服务类的update业务方法
  3. 在控制层的cn.sanqingniao.wfsmw.controller.admin.AdminManageController控制器类的getAdmin和saveAdmin这两个控制方法,这个getAdmin方法用于打开修改页面,这个saveAdmin用于更新用户信息到数据库里。
  4. 在视图层的/resources/templates/admin/admin_edit.html这个视图模板文件。

3.2.3、开发查询管理员功能及其页面

根据第3.2.1节开发思路和顺序,开发查询管理员功能点的持久层Dao接口、SQL脚本映射xml文件、业务服务类、控制器及其页面,具体过程就不再阐述;对于查询功能点,它在每个层级对应的类及其方法说明如下:

  1. 在持久层的cn.sanqingniao.wfsmw.dao.user.UserDao接口里的count和query方法,及其SQL脚本映射UserDao.xml文件的这两个查询元素项;其中count方法是根据查询条件查询总数量,query方法是根据查询条件和页码获取当前页的用户信息列表。
  2. 在业务服务层的cn.sanqingniao.wfsmw.service.user.UserService服务类的getUserList业务方法。
  3. 在控制层的cn.sanqingniao.wfsmw.controller.admin.AdminManageController控制器类的queryAdminList这个控制方法。
  4. 在视图层的/resources/templates/admin/admin_manage.html这个视图模板文件。

3.2.4、开发启用和禁用管理员功能

根据第3.2.1节开发思路和顺序,开发启用和禁用管理员功能点的持久层Dao接口、SQL脚本映射xml文件、业务服务类、控制器及其页面,具体过程就不再阐述;对于启用和禁用功能点,它在每个层级对应的类及其方法说明如下:

  1. 在持久层的cn.sanqingniao.wfsmw.dao.user.UserDao接口里的updateUserStatus方法,及其SQL脚本映射UserDao.xml文件的这个更新元素项。
  2. 在业务服务层的cn.sanqingniao.wfsmw.service.user.UserService服务类的updateUserStatus业务方法。
  3. 在控制层的cn.sanqingniao.wfsmw.controller.admin.AdminManageController控制器类的modifyUserStatus这个控制方法。
  4. 在视图层的/resources/templates/admin/admin_manage.html这个视图模板文件。

综上所述,对于后台管理部分的会员管理、商品管理、订单管理和模块数据管理这些功能的开发思路和顺序,请根据第3.2.1节开发思路和顺序进行开发,具体过程就不再阐述。它们对应的模块名分别是:会员管理模块名是admin、商品管理模块名是goods、订单管理模块名是order、模块数据管理模块名是site,这些功能的全部源代码,请到本项目代码库里去查看。

3.3、开发会员管理功能及其页面

根据第3.2.1节开发思路和顺序,开发会员管理功能点的持久层Dao接口、SQL脚本映射xml文件、业务服务类、控制器及其页面,具体过程就不再阐述;在会员管理功能里,具体有查询会员列表、查看会员详情、启用、禁用这些功能点;对于这些功能点,它在每个层级对应的类及其方法说明如下:

  1. 在持久层的cn.sanqingniao.wfsmw.dao.user.UserDao接口里的一些方法,及其SQL脚本映射UserDao.xml文件的一些元素项。
  2. 在业务服务层的cn.sanqingniao.wfsmw.service.user.UserService服务类的一些业务方法。
  3. 在控制层的cn.sanqingniao.wfsmw.controller.admin.UserManageController控制器类的queryUserList这个控制方法,以及cn.sanqingniao.wfsmw.controller.admin.AdminManageController控制器类的一些方法。
  4. 在视图层的/resources/templates/admin/user_manage.html和/resources/templates/admin/user_edit.html这两个视图模板文件。

3.4、开发商品模块功能及其页面

根据第3.2.1节开发思路和顺序,开发商品模块功能点的持久层Dao接口、SQL脚本映射xml文件、业务服务类、控制器及其页面,具体过程就不再阐述;在商品模块功能里,分商品分类、商品管理和添加商品这三个子模块;具体有对商品分类的增加、修改、删除、查询和浏览这些功能点;对商品的增加、修改、删除、查询、上架、下架和恢复这些功能点;对于这些功能点,它们在每个层级对应的类及其方法说明如下:

  1. 在持久层的cn.sanqingniao.wfsmw.dao.goods.GoodsCategoryDao、cn.sanqingniao.wfsmw.dao.goods.GoodsDao和cn.sanqingniao.wfsmw.dao.goods.GoodsFileDao这三个接口里的一些方法,及其SQL脚本映射GoodsCategoryDao.xml、GoodsDao.xml和GoodsFileDao.xml这三个文件的一些元素项。
  2. 在业务服务层的cn.sanqingniao.wfsmw.service.goods.GoodsCategoryService和cn.sanqingniao.wfsmw.service.goods.GoodsService服务类的一些业务方法。
  3. 在控制层的cn.sanqingniao.wfsmw.controller.goods.GoodsManageController、cn.sanqingniao.wfsmw.controller.goods.GoodsEditController和cn.sanqingniao.wfsmw.controller.goods.GoodsCategoryController这三个控制器类的一些控制方法。
  4. 在视图层的/resources/templates/goods/goods_category.html、/resources/templates/goods/goods_edit.html和/resources/templates/goods/goods_manage.html这三个视图模板文件。

3.5、开发订单模块功能及其页面

根据第3.2.1节开发思路和顺序,开发订单模块功能点的持久层Dao接口、SQL脚本映射xml文件、业务服务类、控制器及其页面,具体过程就不再阐述;在订单模块功能里,具体有对订单的搜索、出库、查看、编辑、取消、完成和修改这些功能点;对于这些功能点,它们在每个层级对应的类及其方法说明如下:

  1. 在持久层的cn.sanqingniao.wfsmw.dao.order.OrderDao和cn.sanqingniao.wfsmw.dao.order.Order2GoodsDao这两个接口里的一些方法,及其SQL脚本映射OrderDao.xml和Order2GoodsDao.xml这两个文件的一些元素项。
  2. 在业务服务层的cn.sanqingniao.wfsmw.service.order.OrderService服务类的一些业务方法。
  3. 在控制层的cn.sanqingniao.wfsmw.controller.order.OrderManageController和cn.sanqingniao.wfsmw.controller.order.OrderApiController这两个控制器类的一些控制方法。
  4. 在视图层的/resources/templates/order/user_order_manage.html、/resources/templates/order/user_order_view.html和/resources/templates/order/user_order_edit.html这三个视图模板文件。

3.6、开发模块数据管理功能及其页面

根据第3.2.1节开发思路和顺序,开发模块数据管理功能点的持久层Dao接口、SQL脚本映射xml文件、业务服务类、控制器及其页面,具体过程就不再阐述;在模块数据管理功能里,具体有对模块数据的搜索、新增、修改、删除、显示和隐藏这些功能点;对于这些功能点,它们在每个层级对应的类及其方法说明如下:

  1. 在持久层的cn.sanqingniao.wfsmw.dao.site.SitePageModuleDao这个接口里的一些方法,及其SQL脚本映射SitePageModuleDao.xml这个文件的一些元素项。
  2. 在业务服务层的cn.sanqingniao.wfsmw.service.site.SitePageModuleService服务类的一些业务方法。
  3. 在控制层的cn.sanqingniao.wfsmw.controller.site.SitePageModuleController这个控制器类的所有控制方法。
  4. 在视图层的/resources/templates/module/module_data_manage.html和/resources/templates/module/module_data_edit.html这两个视图模板文件。

第4节、会员中心

本小节是对会员中心部分的功能进行开发和详细说明;根据第二章概述,会员中心部分含有会员注册及登录、我的订单、个人信息、收货地址和修改密码这些功能及其页面。根据项目架构规划,这些功能及其页面属于会员中心模块,该模块名是member,它们的代码开发说明如下。

4.1、开发会员注册功能及其页面

根据第3.2.1节开发思路和顺序,开发会员注册功能点的持久层Dao接口、SQL脚本映射xml文件、业务服务类、控制器及其页面,具体过程就不再阐述;对于该功能点,它在每个层级对应的类及其方法说明如下:

  1. 在持久层的cn.sanqingniao.wfsmw.dao.user.UserDao接口里的insert方法,及其SQL脚本映射UserDao.xml文件的这个新增元素项。
  2. 在业务服务层的cn.sanqingniao.wfsmw.service.user.UserService服务类的insert业务方法。
  3. 在控制层的cn.sanqingniao.wfsmw.controller.member.MemberRegisterController控制器类的getRegisterPage和registerWeb这两个控制方法,这个getRegisterPage方法用于打开会员注册页面,这个registerWeb方法用于保存注册会员信息到数据库里。
  4. 在视图层的/resources/templates/member/wap_register.html这个视图模板文件。在该页面里使用到Ajax异步技术,在它包含的common_register.html模板片段文件的doRegister()方法里,使用/resources/static/js/commons.js文件里ajaxPostJson封装方法来发起Ajax异步请求注册。

3.2、开发会员登录功能及其页面

根据第3.2.1节开发思路和顺序,开发会员登录功能点的持久层Dao接口、SQL脚本映射xml文件、业务服务类、控制器及其页面,具体过程就不再阐述;对于该功能点,它在每个层级对应的类及其方法说明如下:

  1. 在持久层的cn.sanqingniao.wfsmw.dao.user.UserDao接口里的getUserByName方法,及其SQL脚本映射UserDao.xml文件的这个查询元素项。
  2. 在业务服务层的cn.sanqingniao.wfsmw.service.site.SitePageModuleService服务类的getIndexData业务方法。
  3. 在控制层的cn.sanqingniao.wfsmw.controller.site.SiteIndexController控制器类的index和openIndex这两个控制方法,这两个方法用于打开网站首页页面。
  4. 在视图层的/resources/templates/site/wap_index.html这个视图模板文件。

5.2、开发商品模块前端页面

根据第3.2.1节开发思路和顺序,开发商品模块前端页面功能点的持久层Dao接口、SQL脚本映射xml文件、业务服务类、控制器及其页面,具体过程就不再阐述;在商品模块前端页面里,分商品列表页面、商品详细页面和搜索商品页面这三个前端页面;对于这些功能点,它在每个层级对应的类及其方法说明如下:

  1. 在持久层的cn.sanqingniao.wfsmw.dao.goods.GoodsDao、cn.sanqingniao.wfsmw.dao.goods.GoodsCategoryDao和cn.sanqingniao.wfsmw.dao.site.SitePageModuleDao这三个接口里的一些方法,及其SQL脚本映射GoodsDao.xml、GoodsCategoryDao.xml和SitePageModuleDao.xml这三个文件的一些元素项。
  2. 在业务服务层的cn.sanqingniao.wfsmw.service.goods.GoodsService、cn.sanqingniao.wfsmw.service.goods.GoodsCategoryService和cn.sanqingniao.wfsmw.service.site.SitePageModuleService服务类的一些业务方法。
  3. 在控制层的cn.sanqingniao.wfsmw.controller.site.GoodsController控制器类的所有方法,其中getGoodsListPage方法用于打开商品列表页面,getGoodsDetailPage方法用于打开商品详情页面,getSearchResultPage方法用于打开搜索商品页面,getGoodsList方法用于在商品列表页面通过Ajax异步获取商品信息。
  4. 在视图层的/resources/templates/site/wap_snacks.html、/resources/templates/site/wap_snacks_detail.html和/resources/templates/site/wap_search_result.html这三个视图模板文件。在wap_snacks.html页面里使用到Ajax异步技术,在用户往下拉列表页面时异步获取商品信息。

5.3、开发模块数据列表页面

根据第3.2.1节开发思路和顺序,开发模块数据列表页面功能点的持久层Dao接口、SQL脚本映射xml文件、业务服务类、控制器及其页面,具体过程就不再阐述;对于该功能点,它在每个层级对应的类及其方法说明如下:

  1. 在持久层的cn.sanqingniao.wfsmw.dao.site.SitePageModuleDao接口里的getAllByType方法,及其SQL脚本映射SitePageModuleDao.xml文件的查询元素项。
  2. 在业务服务层的cn.sanqingniao.wfsmw.service.order.OrderService服务类的getByOrderNumber业务方法。
  3. 在控制层的cn.sanqingniao.wfsmw.controller.member.ShoppingResultController控制器类的getShoppingResultPage控制方法。
  4. 在视图层的/resources/templates/site/wap_shopping_result.html和/resources/templates/site/wap_shopping_error.html这两个视图模板文件。

5.9、开发支付宝支付功能

关于支付宝支付功能,它根据客户端不同分不同支付方式,主要分电脑网站支付、手机网站支付、APP支付等等。在我们项目里主要实现这三种支付方式。

5.9.1、引入支付宝支付SDK

支付宝开放平台,其访问网站URL为:https://open.alipay.com/。为了方便第三方公司开发者开发支付宝在线支付功能,该平台提供了SDK包。本项目是以Maven来管理项目依赖包,因此支付宝支付SDK包在配置pom.xml文件中的Maven配置代码。

  com.alipay.sdk

  alipay-sdk-java

  4.35.79.ALL

5.9.2、支付宝支付API说明

支付宝平台对不同支付方式,提供不同API。

对于电脑网站支付的API开发文档,它的访问URL为:https://opendocs.alipay.com/open/repo-0038oa?ref=api,在该开发文档里详细描述产品介绍、接入准备、接入指南、API列表、常见问题,其中在API列表里详细说明了每个API的每个参数名称、类型和意思。

对于手机网站支付的API开发文档,它的访问URL为:https://opendocs.alipay.com/open/repo-0038v7?ref=api,在该开发文档里详细描述产品介绍、接入准备、接入指南、API列表、常见问题,其中在API列表里详细说明了每个API的每个参数名称、类型和意思。

对于APP支付的API开发文档,它的访问URL为:https://opendocs.alipay.com/open/repo-0038v9?ref=api,在该开发文档里详细描述产品介绍、接入准备、接入指南、API列表、常见问题,其中在API列表里详细说明了每个API的每个参数名称、类型和意思。

对于上述这三种支付宝支付方式,它们向支付宝平台发起统一下单请求的网关URL是一样的,即为:https://openapi.alipaydev.com/gateway.do;只是它们的接口名称method及其它参数不一样而已。

5.9.3、开发支付宝支付功能

为了开放支付宝支付功能,根据支付宝开放平台要求,首先必须要在该平台里注册一个开发者账户;然后创建一个应用,得到APPID;之后配置应用,主要是配置两对秘钥,一个是支付宝方的一对公钥与私钥,一个开发者方的一对公钥与私钥;再配置应用网关,即我们系统提供一个接口,用于接收支付宝异步通知消息;最后向支付宝开发平台申请开通上述三种支付方式的产品。

根据我们项目的架构规划,当系统需要向第三方系统获取功能服务时,要求编写一个业务处理器类,用于封装第三方系统提供的功能服务业务执行流程;并且把这些业务处理器类统一保存到handler子包里,其全路径是:wfsmw\src\main\java\cn.sanqingniao.commons.handler;由于支付功能编写的业务处理器类比较多,因此再建立一个pay子包,把这些支付业务处理器类统一保存在这个pay子包里,其全路径是:wfsmw\src\main\java\cn.sanqingniao.commons.handler.pay。

对于支付宝支付功能,由于上述三种支付方式的统一下单请求的网关URL是一样的,因此可以把相关业务执行流程封装在一起,在本项目里定义了AbstractAlipayServiceHandler抽象类,其全路径是:main\java\cn.sanqingniao.commons.handler.pay.AbstractAlipayServiceHandler.java,这个抽象类的核心代码如下:

1行  public abstract class AbstractAlipayServiceHandler extends ServiceHandlerAdapter {

2行      @Value(value = "${commons.alipay.pay.gateway.url}")

3行      private String gatewayUrl;

4行      @Value(value = "${commons.alipay.pay.appid}")

5行      private String alipayAppId;

6行      @Value(value = "${commons.alipay.pay.private.key}")

7行      private String alipayWePrivateKey;

8行      @Value(value = "${commons.alipay.pay.public.key}")

9行      protected String alipayThirdPublicKey;

10行      @Override

11行      public void service() {

12行          try {

13行              AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl, alipayAppId, alipayWePrivateKey, FORMAT_TYPE, DEFAULT_CHARSET_NAME, alipayThirdPublicKey, SIGN_TYPE_RSA2);

14行              if (isAppPay()) {

15行                  response = alipayClient.sdkExecute(getAlipayRequest());

16行              } else if (isRefundRequest()) {

17行                  response = alipayClient.execute(getAlipayRequest());

18行              } else {

19行                  response = alipayClient.pageExecute(getAlipayRequest());

20行              }

21行              if (response.isSuccess()) {

22行                  isSuccess = true;

23行                  alipayRequestBody = response.getBody();

24行              } else {

25行                  isSuccess = false;

26行              }

27行          } catch (Exception e) {

28行              isSuccess = false;

29行              logger.error("执行支付宝支付请求时异常", e);

30行          }

31行      }

32行      public abstract AlipayRequest getAlipayRequest();

33行  }

由于使用了支付宝SDK,可以直接调用里面相关类,因此编写的支付下单代码比较简单。第1行代码定义了AbstractAlipayServiceHandler这个抽象类,它继承了ServiceHandlerAdapter这个业务处理器适配器类,表明这个抽象类是业务处理器类。第3行代码是通过注解注入支付宝支付的统一下单网关URL。第5行代码是在支付宝开放平台注册开发者账户,然后创建应用得到的App ID,并且通过注解注入进来。第7行代码是通过注解注入开发者方的加密解密用的一对密钥的私钥。第9行代码是通过注解注入支付宝方的加密解密用的一对密钥的公钥。第11行代码就是实现业务处理器的主方法service方法,在该方法里实现封装向支付宝发起支付请求的业务流程。第13行代码就是创建支付宝支付客户端对象。第15行代码就是向支付宝发起APP支付请求。第17行代码就是向支付宝发起退款请求。第19行代码就是向支付宝发起网页支付请求,这里包含电脑网站支付和手机网站支付两种方式。在这些请求里都统一调用了一个获取支付请求参数的抽象方法,即第32行代码声明的抽象方法。

对于每个支付宝支付方式,只需要创建对应的业务处理器,并且继承上述抽象类,以及实现getAlipayRequest这个抽象方法就行。

因此支付宝电脑网站支付实现的业务处理器类为AlipayPCPayServiceHandler,其全路径是:main\java\cn.sanqingniao.commons.handler.pay.AlipayPCPayServiceHandler.java。

支付宝手机网站支付实现的业务处理器类为AlipayWapPayServiceHandler,其全路径是:main\java\cn.sanqingniao.commons.handler.pay.AlipayWapPayServiceHandler.java。

因此支付宝电脑网站支付实现的业务处理器类为AlipayAppPayServiceHandler,其全路径是:main\java\cn.sanqingniao.commons.handler.pay.AlipayAppPayServiceHandler.java。

上述这些支付功能的全部源代码,请到本项目代码库里去查看。

如此实现了支付宝的电脑网站支付、手机网站支付、APP支付这三种支付方式,之后只需要在提交订单功能的业务流程里,调用这些业务处理器,就能实现支付宝在线支付功能。

5.9.4、调用支付宝支付功能及其页面

在第《5.7、开发提交订单页面》小节描述的业务流程里,当用户选择支付宝支付订单的时候,就得调用支付宝相关支付业务处理器,具体调用代码如下。

在控制层的cn.sanqingniao.wfsmw.controller.member.ShoppingCartController控制器类的getShoppingSubmitPage控制方法,通过如下一段代码来调用支付宝相关支付业务处理器:

......

         1行   switch (userOrder.getPayType()) {

         2行       case PAY_TYPE_WEIXIN:

         3行           payRequestSuccess = createWeiXinPayRequest(userOrder, modelMap);

         4行           break;

         5行       case PAY_TYPE_ALIPAY:

         6行           payRequestSuccess = createAlipayPayRequest(userOrder, modelMap);

         7行           break;

         8行       case PAY_TYPE_COD:

         9行           // 获取购物结果模板页面

         10行           pageViewName = "site/wap_shopping_result";

         11行           break;

         12行   }

......

其中第6行代码就是调用支付宝相关支付业务处理器的封装方法createAlipayPayRequest,其详细代码如下:

1行  protected boolean createAlipayPayRequest(OrderEntity userOrder, ModelMap modelMap) {

2行      boolean payRequestSuccess = true;

3行      AbstractAlipayServiceHandler alipayHandler;

4行      if (userOrder.getClientType() == CLIENT_TYPE_PC) {

5行          alipayHandler = context.getBean("alipayPCPayServiceHandler", AlipayPCPayServiceHandler.class);

6行      } else {

7行          alipayHandler = context.getBean("alipayWapPayServiceHandler", AlipayWapPayServiceHandler.class);

8行      }

9行      alipayHandler.setUserOrder(userOrder);

10行      alipayHandler.service();

11行      if (alipayHandler.isSuccess()) {

12行          modelMap.addAttribute("submitPayRequest", alipayHandler.getAlipayRequestBody());

13行      } else {

14行          logger.error("该订单({})向支付宝发起支付请求失败!", userOrder.getOrderNumber());

15行          modelMap.addAttribute(ERROR_MSG_KEY, getText("common.submit.pay.request.failure", "支付宝"));

16行          payRequestSuccess = false;

17行      }

18行      modelMap.addAttribute(PAYMENT_ACCOUNT_TYPE_KEY, PAY_ACCOUNT_TYPE_ALIPAY);

19行      return payRequestSuccess;

20行  }

在这个方法里只调用了电脑网站支付和手机网站支付这两种业务请求处理器,分别对应第5行和第7行代码。第10行代码就是向支付宝平台发起统一下单支付请求。如果请求成功,那么得到一个能在电脑端或者手机端显示支付页面的结果字符串,如在第12行代码把这个结果字符串保存到用于显示支付页面的视图层的/resources/templates/site/shopping_submit.html这个视图模板文件里。

5.9.5、开发接收支付宝异步通知消息功能

当下单用户通过他自己的支付宝账户支付金钱成功之后,支付宝平台会异步回调我们之前在应用配置里应用网关接口,来通知我们支付结果;因此我们要开发一个这样的网关接口;在该接口里我们要实现的业务是检查用户订单的支付状态合法性,如果合法,那么更新用户订单的支付状态和订单里商品的库存和销量;它在每个层级对应的类及其方法说明如下:

  1. 在持久层的cn.sanqingniao.wfsmw.dao.order.OrderDao接口里的getByOrderNumber和updatePayById方法,cn.sanqingniao.wfsmw.dao.order.Order2GoodsDao的getBaseByOrderId方法和cn.sanqingniao.wfsmw.dao.goods.GoodsDao的updateSalesVolumeById方法,及其SQL脚本映射OrderDao.xml、Order2GoodsDao.xml和GoodsDao.xml文件的一些元素项。
  2. 在业务服务层的cn.sanqingniao.wfsmw.service.order.OrderService服务类的getByOrderNumber和savePayResultById业务方法。
  3. 在控制层的cn.sanqingniao.wfsmw.controller.member.ShoppingResultController控制器类的handlerAlipayResultNotify控制方法。
  4. 在控制层的拦截器的不拦截路径模式里,增加这个网关接口URL,以便不被登录认证拦截,即在cn.sanqingniao.wfsmw.WfsmwWebMvcConfigurer的addInterceptors方法,增加这一行代码:excludePathPatterns("/member/shopping_result.html", "/member/alipay_result_notify.html")。

上述这些接收支付宝异步通知消息功能的全部源代码,请到本项目代码库里去查看。

5.10、开发微信支付功能

关于微信支付功能,其开发流程和步骤与支付宝支付功能一样,大同小异,具体过程就不再阐述,微信开放平台的访问网站URL是:https://open.weixin.qq.com/。对于该支付功能,它在每个层级对应的类及其方法说明如下:

  1. 在业务处理器层的业务处理器类有在cn.sanqingniao.commons.handler.pay子包的AbstractWeiXinPayServiceHandler、WeiXinPrepayRequestServiceHandler、WeiXinNotifyServiceHandler、WeiXinQueryRequestServiceHandler这四个支付业务处理器类。
  2. 在持久层的cn.sanqingniao.wfsmw.dao.user.ShoppingCartDao、cn.sanqingniao.wfsmw.dao.order.OrderDao、cn.sanqingniao.wfsmw.dao.order.Order2GoodsDao、cn.sanqingniao.wfsmw.dao.goods.GoodsDao接口的一些方法,及其SQL脚本映射ShoppingCartDao.xml、OrderDao.xml、Order2GoodsDao.xml和GoodsDao.xml文件的一些元素项。
  3. 在业务服务层的cn.sanqingniao.wfsmw.service.member.ShoppingCartService、cn.sanqingniao.wfsmw.service.order.OrderService服务类的一些业务方法。
  4. 在控制层的cn.sanqingniao.wfsmw.controller.member.ShoppingCartController的getShoppingSubmitPage控制方法,它用于创建用户订单和发起在线微信支付请求;在cn.sanqingniao.wfsmw.controller.member.ShoppingResultController控制器类的handlerWeiXinPayResultNotify控制方法,用于接收微信支付平台的支付结果异步通知消息。
  5. 在控制层的拦截器的不拦截路径模式里,增加这个网关接口URL,以便不被登录认证拦截,即在cn.sanqingniao.wfsmw.WfsmwWebMvcConfigurer的addInterceptors方法,增加这一行代码:excludePathPatterns("/member/shopping_result.html", "/member/wei_xin_pay_result_notify.html")。

上述这些微信支付功能的全部源代码,请到本项目代码库里去查看。

你可能感兴趣的:(java,maven,spring,spring,boot,mybatis)