JAVA WEB快速入门之从编写一个基于SpringBoot+Mybatis快速创建的REST API项目了解SpringBoot、SpringMVC REST API、Mybatis等相关知识

JAVA WEB 快速入门系列之前的相关文章如下:(文章全部本人【梦在旅途原创】,文中内容可能部份图片、代码参照网上资源)

第一篇:JAVA WEB 快速入门之环境搭建

第二篇:JAVA WEB 快速入门之从编写一个 JSP WEB 网站了解 JSP WEB 网站的基本结构、调试、部署

第三篇:JAVA WEB 快速入门之通过一个简单的 Spring 项目了解 Spring 的核心(AOP、IOC)

第四篇:JAVA WEB 快速入门之从编写一个基于 SpringMVC 框架的网站了解 Maven、SpringMVC、SpringJDBC

 

今天是第五篇,也是该系列文章的最后一篇,接上篇《JAVA WEB 快速入门之从编写一个基于 SpringMVC 框架的网站了解 Maven、SpringMVC、SpringJDBC》,通过上篇文章的详细介绍,知道如何使用 maven 来快速构建 spring MVC 应用,也能够使用 spring MVC+springJDBC 实现网站开发,而本文所涉及的知识则是在这基础之上继续提升,核心是讲解如何使用 spring boot 来更快速的构建 spring MVC,并通过 mybatis 及代码生成相关 DAO,同时利用 VUE 前端框架开发前后端分离的网站,用户体验更好,废话不多说,直接进入本文主题。

(提示:本文内容有点长,涉及的知识点也比较多,若是新手建议耐心看完!)

一、创建 Spring Boot+SpringMVC 空项目

  1.1 通过 https://start.spring.io/ 官网快速生成一个 Spring Boot+SpringMVC 空项目,如下图示:

(当然也可以通过 Eclipse 或 IDEA 的 Spring Boot 插件来创建,可参见:https://www.cnblogs.com/shaoniandream/p/9679942.htmlhttps://blog.csdn.net/qq_32572497/article/details/62037873

  

  设置后点击页面的生成项目按钮,即可生成并下载 spring boot 项目代码压缩包,然后使用 IDE 导入存在的 maven project 即可。

  1.2 调整项目,解决一些踩坑点

  1.2.1. 调整 spring boot App 启动类(如:SpringbootdemoApplication)到根包目录或在启动类上显式添加 @ComponentScan 注解,并指定包路径,如下代码所示,cn.zuowenjun.boot 是根包目录,其余都是 cn.zuowenjun.boot 的子包

package cn.zuowenjun.boot;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
//import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
//指定为 Spring Boot 启动入口,内含多个 spring 所需要的注解
@MapperScan(basePackages="cn.zuowenjun.boot.mapper")//设置 Mybaits 扫描的 mapper 包路径
//@ComponentScan(basePackages= {"cn.zuowenjun.controller"}) //如果不在根包目录,则需指定 spring 管理的相关包路径
@EnableTransactionManagement //启动事务管理
public class SpringbootdemoApplication {

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
    SpringApplication.run(SpringbootdemoApplication.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">, args);
}

}

  1.2.2. 解决 POM 文件报:

Description Resource Path Location Type
Execution default-resources of goal org.apache.maven.plugins:maven-resources-plugin:3.1.0:resources failed: Unable to load the mojo 'resources' (or one of its required components) from the plugin 'org.apache.maven.plugins:maven-resources-plugin:3.1.0'

直接在 POM 中添加如下 resources 依赖:

        <dependency>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <version>2.5</version>
            <type>maven-plugin</type>
        </dependency>

  1.2.3. 设置热编译启动模式,以便可以随时更改代码后即时生效

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
   </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <fork>true</fork>
            </configuration>
        </plugin>
   </plugins>
</build>

设置后项目的视图就有如下显示效果:

  1.3 演示请求 REST API 分别返回 JSON、XML

   创建好 spring boot 空项目环境后,我们就可以开始编写相关代码了,在此仅贴出实现了 REST API 分别响应返回 JSON、XML 格式的 Controller,实现步骤如下:

   1.3.1 在 cn.zuowenjun.boot.controller 包中创建 DemoController,并编写 hellojson、helloxml Action 方法,代码如下:

package cn.zuowenjun.boot.controller;

import org.springframework.web.bind.annotation.*;

import cn.zuowenjun.boot.domain.*;

@RestController
public class DemoController {

@RequestMapping(value</span>="/hello/json",produces="application/json;charset=utf-8"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> HelloDto hellojson()
{
    HelloDto dto</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> HelloDto();
    dto.setMessage(</span>"hello,zuowenjun.cn,hello java spring boot!"<span style="color: rgba(0, 0, 0, 1)">);
    
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> dto;
}

@RequestMapping(value</span>="/hello/xml",produces="text/xml;charset=utf-8"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> HelloDto helloxml()
{
    HelloDto dto</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> HelloDto();
    dto.setMessage(</span>"hello,zuowenjun.cn,hello java spring boot!"<span style="color: rgba(0, 0, 0, 1)">);
    
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> dto;
}

}

如上代码简要说明:@RestController 相当于是:@Controller、@ResponseBody,这个可以查看 @RestController 注解类代码就知道;@RequestMapping 指定请求映射,其中 produces 设置响应内容格式(可理解为服务端是生产者,而用户在浏览器端【客户端】是消费端),还有 consumes 属性,这个是指可接收请求的内容格式(可理解为用户在浏览器端发送请求是消息的生产者,而服务端接收并处理该请求为消息的消费者),当然还有其它一些属性,大家可以参见我上篇文章或网络其它大神的相关文章加以了解。

另外需要注意,默认 spring MVC 只返回 JSON 格式,若需返回 XML 格式,还需添加 XML JAR 包依赖,如下:(可以看到 version 这里我指定了版本号区间,表示 2.5.0 及以上版本都可以,有些依赖 spring-boot-starter-parent 中都有提前配置依赖管理,我们只需要指定 groupId、artifactId 即可,version 就会使用 spring boot 中的默认版本,当然也可以强制指定版本)

        <!-- 如果项目中需要 REST API 响应(返回)XML 格式的报文体则应添加该依赖 -->
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-xml-provider</artifactId>
            <version>[2.5.0,)</version><!--$NO-MVN-MAN-VER$ -->
        </dependency>

由于项目中同时添加 JSON 及 XML 的 JAR 包,按照 spring MVC 的默认响应处理流程是:如果未指定 produces,则当请求的 header 中指定了 accept 类型,则自动格式化并返回该 accept 所需的类型,如果未指定 accept 类型,则优先是响应 XML,当找不到 XML 依赖包时才会响应 JSON,故如果项目中同时有 JSON 及 XML,那么最好显式指定 produces 或者请求头上指明 accept 类型 这一点与 ASP.NET WEB API 原理相同,因为都是符合 REST 架构风格的。

效果如下:

     

二、使用 Mybatis 框架完成 Domain 层、DAO 层 (这里是 Mapper 层) --- 提示:由于篇幅有限,只贴出重点能体现不同知识点的代码,其余可以到 GITHUB 上查看下载源码进行详细了解

  2.0:首先在 application.properties 配置 mybatis 的相关选项,如下所示:

mybatis.type-aliases-package=cn.zuowenjun.boot.domain #包类型别名,这样在 XML 中就可以简写成类名
mybatis.config-location=classpath:mybatis/mybatis-config.xml #指定 mybatis 的配置文件路径
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml #指定 mapper XML 的存放路径

#这里是使用 SQL SERVER,如果是其它 DB 则使用其它驱动
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.url=jdbc:sqlserver://DBIP:Port;DatabaseName=testDB
spring.datasource.username=dbuser
spring.datasource.password=dbpassword

   其次添加 mybatis-spring-boot-starter maven 依赖, 它会自动添加相关的 mybatis 依赖包,配置如下:

        <!-- 添加 mybatis-spring-boot 依赖,直接可以使用 mybatis 环境操作 DB-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

  2.1 全手写 JAVA 代码实现 Mybatis 的 CRUD;

  2.1.1. 在 cn.zuowenjun.boot.domain 包【实体模型或称领域模型层,这里算不上真正的领域模型,最多算是贫血的领域模型】中定义数据实体模型(Goods: 商品信息),代码如下:

package cn.zuowenjun.boot.domain;

import java.math.BigDecimal;
import java.util.Date;

public class Goods {
private int id;
private String title;
private String picture;
private BigDecimal price;
private String introduction;
private int categoryId;
private String lastEditBy;
private Date lastEditTime;

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Goods() {
    
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> Goods(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id,String title,String picture,
        BigDecimal price,String introduction,</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> categoryId,String lastEditBy,Date lastEditTime) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setId(id);
    </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setTitle(title);
    </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setPicture(picture);
    </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setPrice(price);
    </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setIntroduction(introduction);
    </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setCategoryId(categoryId);
    </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setLastEditBy(lastEditBy);
    </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setLastEditTime(lastEditTime);
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getId() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> id;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setId(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getTitle() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> title;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setTitle(String title) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.title =<span style="color: rgba(0, 0, 0, 1)"> title;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getPicture() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> picture;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setPicture(String picture) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.picture =<span style="color: rgba(0, 0, 0, 1)"> picture;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> BigDecimal getPrice() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> price;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setPrice(BigDecimal price) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.price =<span style="color: rgba(0, 0, 0, 1)"> price;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getIntroduction() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> introduction;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setIntroduction(String introduction) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.introduction =<span style="color: rgba(0, 0, 0, 1)"> introduction;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getCategoryId() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> categoryId;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setCategoryId(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> categoryId) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.categoryId =<span style="color: rgba(0, 0, 0, 1)"> categoryId;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getLastEditBy() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> lastEditBy;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setLastEditBy(String lastEditBy) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.lastEditBy =<span style="color: rgba(0, 0, 0, 1)"> lastEditBy;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Date getLastEditTime() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> lastEditTime;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setLastEditTime(Date lastEditTime) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.lastEditTime =<span style="color: rgba(0, 0, 0, 1)"> lastEditTime;
}

}

View Code

  2.1.2. 在 cn.zuowenjun.boot.mapper 包【数据映射处理层或称 DAO 层】中定义数据映射处理接口及添加相应的 SQL 注解,以实现对数据进行 CRUD,代码如下:

package cn.zuowenjun.boot.mapper;

import java.util.*;

import org.apache.ibatis.annotations.*;

import cn.zuowenjun.boot.domain.*;

public interface GoodsMapper {

@Select(</span>"select * from TA_TestGoods order by id offset (${pageNo}-1)*${pageSize} rows fetch next ${pageSize} rows only"<span style="color: rgba(0, 0, 0, 1)">)
List</span>&lt;Goods&gt; getListByPage(<span style="color: rgba(0, 0, 255, 1)">int</span> pageSize,<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> pageNo);

@Select(</span>"select * from TA_TestGoods where categoryId=#{categoryId} order by id"<span style="color: rgba(0, 0, 0, 1)">)
List</span>&lt;Goods&gt; getList(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> categoryId);

@Select(</span>"&lt;script&gt;select * from TA_TestGoods where id in " 
        +"&lt;foreach item='item' index='index' collection='ids' open='(' separator=',' close=')'&gt;#{item}&lt;/foreach&gt;"
        +"order by id&lt;/script&gt;"<span style="color: rgba(0, 0, 0, 1)">)
List</span>&lt;Goods&gt; getListByMultIds(@Param("ids")<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">...ids);

@Select(</span>"select * from TA_TestGoods where id=#{id}"<span style="color: rgba(0, 0, 0, 1)">)
Goods get(</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id);


@Insert(value</span>="insert into TA_TestGoods(title, picture, price, introduction, categoryId, "
        + "lastEditBy, lastEditTime) values(#{title},#{picture},#{price},#{introduction},#{categoryId},#{lastEditBy},getdate())"<span style="color: rgba(0, 0, 0, 1)">)
@Options(useGeneratedKeys</span>=<span style="color: rgba(0, 0, 255, 1)">true</span>,keyProperty="id",keyColumn="id"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> insert(Goods goods);

@Delete(value</span>="delete from TA_TestGoods where id=#{id}"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">void</span> delete(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id);

@Update(</span>"update TA_TestGoods set title=#{title},picture=#{picture},price=#{price},introduction=#{introduction}," + 
        "categoryId=#{categoryId},lastEditBy=#{lastEditBy},lastEditTime=getdate()  " + 
        "where id=#{id}"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> update(Goods goods);

}

 如上代码重点说明:

a. 增删改查,对应的注解是:insert、delete、update、select;

b.SQL 注解中的参数占位符有两种,一种是:#{xxx},最后会生成? 的参数化执行,另一种是:${xxx} 则最后会直接替换成参数的值,即拼 SQL(除非信任参数或一些时间、数字类型,否则不建议这种,存在 SQL 注入风险);

c.insert 时如果有自增 ID,则可以通过添加 Options 注解,并指定 useGeneratedKeys=true,keyProperty="数据实体类的属性字段名",keyColumn="表自增 ID 的字段名",这样当 insert 成功后会自动回填到数据实体类的自增 ID 对应的属性上;

d. 如果想要生成 in 子句查询,则如上代码 getListByMultIds 方法上的 select 注解中使用 <script>xxx<foreach>xx</foreach>xx</script> 格式实现,如果想用实现复杂的一对一,一对多,多对多等复杂的查询,则需要添加 results 注解并指定相应的关联关系,同时 select SQL 语句也应关联查询,可参见:https://blog.csdn.net/desert568/article/details/79079151

以上 2 步即完成一个 mapper 操作类;

  2.2 全手写 AVA 代码 +Mapper XML 实现 Mybatis 的 CRUD;

  2.2.1. 仍然是在 cn.zuowenjun.boot.domain 包中定义一个数据实体模型类(ShoppingCart:购物车信息),代码如下:【注意这里有一个关联商品信息的属性:inGoods】

package cn.zuowenjun.boot.domain;

import java.util.Date;

public class ShoppingCart {
private int id;
private String shopper;
private int goodsId;
private int qty;
private Date addedTime;
private Goods inGoods;

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> ShoppingCart() {
    
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> ShoppingCart(<span style="color: rgba(0, 0, 255, 1)">int</span> id,String shopper,<span style="color: rgba(0, 0, 255, 1)">int</span> goodsId,<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> qty,Date addedTime) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id=<span style="color: rgba(0, 0, 0, 1)">id;
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.shopper=<span style="color: rgba(0, 0, 0, 1)">shopper;
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.goodsId=<span style="color: rgba(0, 0, 0, 1)">goodsId;
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.qty=<span style="color: rgba(0, 0, 0, 1)">qty;
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.addedTime=<span style="color: rgba(0, 0, 0, 1)">addedTime;
}


</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getId() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> id;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setId(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getShopper() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> shopper;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setShopper(String shopper) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.shopper =<span style="color: rgba(0, 0, 0, 1)"> shopper;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getGoodsId() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> goodsId;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setGoodsId(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> goodsId) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.goodsId =<span style="color: rgba(0, 0, 0, 1)"> goodsId;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getQty() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> qty;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setQty(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> qty) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.qty =<span style="color: rgba(0, 0, 0, 1)"> qty;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Date getAddedTime() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> addedTime;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setAddedTime(Date addedTime) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.addedTime =<span style="color: rgba(0, 0, 0, 1)"> addedTime;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Goods getInGoods() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> inGoods;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setInGoods(Goods inGoods) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.inGoods =<span style="color: rgba(0, 0, 0, 1)"> inGoods;
}

}

View Code

  2.2.2. 仍然是在 cn.zuowenjun.boot.mapper 包中定义数据操作接口(interface),注意这里只是定义接口,并不包含 SQL 注解部份,因为这部份将在 Mapper 的 XML 代码中进行配置实现,代码如下:

package cn.zuowenjun.boot.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import cn.zuowenjun.boot.domain.*;

public interface ShoppingCartMapper {

List</span>&lt;ShoppingCart&gt;<span style="color: rgba(0, 0, 0, 1)"> getList(String shopper);

</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> insert(ShoppingCart shoppingCart);

</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> update(ShoppingCart shoppingCart);

</span><span style="color: rgba(0, 0, 255, 1)">void</span> deleteItem(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id);

</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> delete(String shopper);

</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getBuyCount(String shopper);

ShoppingCart get(@Param(</span>"shopper") String shopper,@Param("goodsId") <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> goodsId); 

}

如上代码有一个重点说明:get 方法有两个参数(多个参数也类似),为了 mybatis 能够自动映射到这些参数,必需为每个参数添加 Param 注解,并指定参数名,这个参数名是与对应的 Mapper XML 中的 SQL 语句中定义的参数名相同。

  2.2.3. 在 mybatis.mapper-locations 设置的 mapper xml 存放的路径中创建 XML 文件,并手动编写映射的 SQL 语句,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.zuowenjun.boot.mapper.ShoppingCartMapper">
    <resultMap id="shoppingCartMap" type="ShoppingCart" >
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="shopper" property="shopper" jdbcType="NVARCHAR" />
        <result column="goodsId" property="goodsId" jdbcType="INTEGER" />
        <result column="qty" property="qty" jdbcType="INTEGER"/>
        <result column="addedTime" property="addedTime" jdbcType="DATE" />
        <!-- referseee https://www.cnblogs.com/ysocean/p/7237499.html -->
        <association property="inGoods" javaType="cn.zuowenjun.boot.domain.Goods">
            <id column="id" property="id" jdbcType="INTEGER" />
            <result column="title" property="title" />
            <result column="picture" property="picture" />
            <result column="price" property="price" />
            <result column="introduction" property="introduction" />
            <result column="categoryId" property="categoryId" />
            <result column="lastEditBy" property="lastEditBy" />
            <result column="lastEditTime" property="lastEditTime" />
        </association>
    </resultMap>
<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 如果返回的结果与某个实体类完全相同,其实完全不需要上面的resultMap,而是直接使用resultType=类名,
    如:resultType=cn.zuowenjun.boot.domain.ShoppingCart(简写别名:ShoppingCart),此处是示例用法,故采取指定映射 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">select </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="getList"</span><span style="color: rgba(255, 0, 0, 1)"> parameterType</span><span style="color: rgba(0, 0, 255, 1)">="string"</span><span style="color: rgba(255, 0, 0, 1)"> resultMap</span><span style="color: rgba(0, 0, 255, 1)">="shoppingCartMap"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)">
    select * from TA_TestShoppingCart a inner join TA_TestGoods b  on a.goodsId=b.id  
    where shopper=#{shopper} order by addedTime
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">select</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">select </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="getBuyCount"</span><span style="color: rgba(255, 0, 0, 1)"> parameterType</span><span style="color: rgba(0, 0, 255, 1)">="string"</span><span style="color: rgba(255, 0, 0, 1)"> resultType</span><span style="color: rgba(0, 0, 255, 1)">="int"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)">
    select count(1) from (select goodsId from TA_TestShoppingCart where shopper=#{shopper} 
    group by goodsId) as t
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">select</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">select </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="get"</span><span style="color: rgba(255, 0, 0, 1)">  resultMap</span><span style="color: rgba(0, 0, 255, 1)">="shoppingCartMap"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)">
     select * from TA_TestShoppingCart a inner join TA_TestGoods b  on a.goodsId=b.id  
     where shopper=#{shopper} and goodsId=#{goodsId}
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">select</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">insert </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="insert"</span><span style="color: rgba(255, 0, 0, 1)"> parameterType</span><span style="color: rgba(0, 0, 255, 1)">="ShoppingCart"</span><span style="color: rgba(255, 0, 0, 1)"> 
    useGeneratedKeys</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(255, 0, 0, 1)"> keyProperty</span><span style="color: rgba(0, 0, 255, 1)">="id"</span><span style="color: rgba(255, 0, 0, 1)"> keyColumn</span><span style="color: rgba(0, 0, 255, 1)">="id"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)">
    insert into TA_TestShoppingCart(shopper, goodsId, qty, addedTime) 
    values(#{shopper},#{goodsId},#{qty},getdate())
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">insert</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">update </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="update"</span><span style="color: rgba(255, 0, 0, 1)"> parameterType</span><span style="color: rgba(0, 0, 255, 1)">="ShoppingCart"</span> <span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)">
    update TA_TestShoppingCart set shopper=#{shopper},goodsId=#{goodsId},qty=#{qty},addedTime=getdate() 
    where id=#{id}
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">update</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">delete </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="deleteItem"</span><span style="color: rgba(255, 0, 0, 1)"> parameterType</span><span style="color: rgba(0, 0, 255, 1)">="int"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)">
    delete from TA_TestShoppingCart where id=#{id}
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">delete</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">delete </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="delete"</span><span style="color: rgba(255, 0, 0, 1)"> parameterType</span><span style="color: rgba(0, 0, 255, 1)">="string"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)">
    delete from TA_TestShoppingCart where shopper=#{shopper}
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">delete</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</mapper>

如上 XML 重点说明:

a. 凡是使用到类型的地方,可以在 mybatis-config.xml 中提前配置类型别名,以简化配置,当然 mybatis 已默认设置了一些别名以减少大家配置的工作量,如:string,对应的类型是 String 等,详见:http://www.mybatis.org/mybatis-3/zh/configuration.html#typeAliases

b. 由于这个 ShoppingCart 有关联属性:inGoods,故在查询时都会关联查询 goods 表并通过在 resultMap 中通过 association 元素来指定关联关系,更多复杂的 XML 配置详见:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html

以上 3 步即完成一个 mapper 操作类,相比直接使用 mapper 接口 +SQL 注解多了一个步骤,但这样的好处是由于没有写死在代码中,可以很容易的更改 mapper 的相关 SQL 语句,减少代码改动量。

  2.3 使用 Mybatis Generator 的 Maven 插件自动生成 Mybatis 的 CRUD;

   通过上面的介绍,我们知道有 2 种方法来实现一个 mapper 数据操作类(dao),显然第 2 种更能适应更改的情况,但由于手写 mapper xml 文件非常的麻烦,故可以通过Mybatis Generator 组件,自动生成相关的代码及 xml(一般是:数据实体类 domain、数据处理接口 mapper、mapper XML),具体实现步骤如下:(可以单独一个项目来生成这些文件,也可以集成在一个项目中,由于是演示,我这里是集成在一个项目中)

  2.3.1. 由于要使用Mybatis Generator 组件,故需要添加对应的 JAR 包依赖,如下所示:

        <!--SQL SERVER 数据驱动,以提供数据访问支持-->
<dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
            <version>7.0.0.jre8</version><!--$NO-MVN-MAN-VER$ -->
        </dependency>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 添加mybatis生成器,以便通过maven build自动生成model、mapper及XML </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.mybatis.generator<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>mybatis-generator-core<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>1.3.7<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>

同时需要添加对应的 maven 插件,以便通过 maven 命令可执行生成过程,如下:(通过 configurationFile 元素指定生成器的配置路径,overwrite 元素指定是否覆盖生成,这里有个坑,后面会介绍到,此处略)

<build>
        <plugins>            
      <plugin>
                <!--ref: https://gitee.com/free/Mybatis_Utils/blob/master/MybatisGeneator/MybatisGeneator.md -->
                <!--ref: https://www.cnblogs.com/handsomeye/p/6268513.html -->
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.7</version>
                <configuration>
                    <configurationFile>src/main/resources/mybatis/generatorconfig.xml</configurationFile>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>
        </plugins>
  </build>

 2.3.2. 在 cn.zuowenjun.boot.domain 包中定义相关的数据实体模型类,我这里演示的类是:ShoppingOrder(购物订单信息),代码如下:

package cn.zuowenjun.boot.domain;

import java.math.BigDecimal;
import java.util.Date;

public class ShoppingOrder {
private Integer id;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String shopper;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Integer totalqty;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> BigDecimal totalprice;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Boolean iscompleted;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String createby;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Date createtime;

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Integer getId() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setId(Integer id) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getShopper() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> shopper;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setShopper(String shopper) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.shopper = shopper == <span style="color: rgba(0, 0, 255, 1)">null</span> ? <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)"> : shopper.trim();
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Integer getTotalqty() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> totalqty;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setTotalqty(Integer totalqty) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.totalqty =<span style="color: rgba(0, 0, 0, 1)"> totalqty;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> BigDecimal getTotalprice() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> totalprice;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setTotalprice(BigDecimal totalprice) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.totalprice =<span style="color: rgba(0, 0, 0, 1)"> totalprice;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Boolean getIscompleted() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> iscompleted;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setIscompleted(Boolean iscompleted) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.iscompleted =<span style="color: rgba(0, 0, 0, 1)"> iscompleted;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getCreateby() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> createby;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setCreateby(String createby) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.createby = createby == <span style="color: rgba(0, 0, 255, 1)">null</span> ? <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)"> : createby.trim();
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Date getCreatetime() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> createtime;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setCreatetime(Date createtime) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.createtime =<span style="color: rgba(0, 0, 0, 1)"> createtime;
}

}

View Code

  2.3.3. 配置 generatorconfig.xml,指定生成的各个细节,由于 generatorconfig 的配置节点比较多, 如下只是贴出当前示例的配置信息,有一点要说明,注意配置节点的顺序,如果顺序不对就会报错,完整的配置方法详情介绍可参见:https://gitee.com/free/Mybatis_Utils/blob/master/MybatisGeneator/MybatisGeneator.md 或 https://www.cnblogs.com/handsomeye/p/6268513.html

<?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="application.properties" />
    <!-- https://blog.csdn.net/zsy3313422/article/details/53190613 -->
    <classPathEntry
        location="E:/LocalMvnRepositories/com/microsoft/sqlserver/mssql-jdbc/7.0.0.jre8/mssql-jdbc-7.0.0.jre8.jar" />
    <context id="my" targetRuntime="MyBatis3Simple" defaultModelType="flat">
        <property name="javaFileEncoding" value="UTF-8" />
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">commentGenerator</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="suppressAllComments"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="true"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="suppressDate"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="true"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">commentGenerator</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">jdbcConnection
        </span><span style="color: rgba(255, 0, 0, 1)">driverClass</span><span style="color: rgba(0, 0, 255, 1)">="${spring.datasource.driverClassName}"</span><span style="color: rgba(255, 0, 0, 1)">
        connectionURL</span><span style="color: rgba(0, 0, 255, 1)">="${spring.datasource.url}"</span><span style="color: rgba(255, 0, 0, 1)">
        userId</span><span style="color: rgba(0, 0, 255, 1)">="${spring.datasource.username}"</span><span style="color: rgba(255, 0, 0, 1)">
        password</span><span style="color: rgba(0, 0, 255, 1)">="${spring.datasource.password}"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">jdbcConnection</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 生成model实体类文件位置 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">javaModelGenerator
        </span><span style="color: rgba(255, 0, 0, 1)">targetPackage</span><span style="color: rgba(0, 0, 255, 1)">="cn.zuowenjun.boot.domain"</span><span style="color: rgba(255, 0, 0, 1)">
        targetProject</span><span style="color: rgba(0, 0, 255, 1)">="src/main/java"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="enableSubPackages"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="false"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="trimStrings"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="true"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">javaModelGenerator</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 生成mapper.xml配置文件位置 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> targetPackage这里指定包名,则会在如下的路径中生成多层级目录 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">sqlMapGenerator </span><span style="color: rgba(255, 0, 0, 1)">targetPackage</span><span style="color: rgba(0, 0, 255, 1)">="mybatis.mapper"</span><span style="color: rgba(255, 0, 0, 1)">
        targetProject</span><span style="color: rgba(0, 0, 255, 1)">="src/main/resources"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="enableSubPackages"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="false"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">sqlMapGenerator</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 生成mapper接口文件位置 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">javaClientGenerator
        </span><span style="color: rgba(255, 0, 0, 1)">targetPackage</span><span style="color: rgba(0, 0, 255, 1)">="cn.zuowenjun.boot.mapper"</span><span style="color: rgba(255, 0, 0, 1)">
        targetProject</span><span style="color: rgba(0, 0, 255, 1)">="src/main/java"</span><span style="color: rgba(255, 0, 0, 1)"> type</span><span style="color: rgba(0, 0, 255, 1)">="XMLMAPPER"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="enableSubPackages"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="false"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">javaClientGenerator</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">table </span><span style="color: rgba(255, 0, 0, 1)">tableName</span><span style="color: rgba(0, 0, 255, 1)">="TA_TestShoppingOrder"</span><span style="color: rgba(255, 0, 0, 1)">
        domainObjectName</span><span style="color: rgba(0, 0, 255, 1)">="ShoppingOrder"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">generatedKey </span><span style="color: rgba(255, 0, 0, 1)">column</span><span style="color: rgba(0, 0, 255, 1)">="id"</span><span style="color: rgba(255, 0, 0, 1)"> sqlStatement</span><span style="color: rgba(0, 0, 255, 1)">="JDBC"</span><span style="color: rgba(255, 0, 0, 1)">  identity</span><span style="color: rgba(0, 0, 255, 1)">="true"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span><span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 指示ID为自增ID列,并在插入后返回该ID </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">table</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>



<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">context</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</generatorConfiguration>

View Code

由于涉及的知识点比较多,在此就不作介绍,请参见我给出的链接加以了解。

  2.3.4. 通过 maven 插件来执行生成代码(生成代码有很多种方法,详见:https://blog.csdn.net/qq_32786873/article/details/78226925),这里我使用最为方便的一种,步骤如下:

  项目右键 -》RunAs 或者 DeBug-》Maven Build...-》在 goals(阶段)中输入:mybatis-generator:generate,即:设置生成阶段,最后点击 Apply 或直接 Run 即可,如图示:

  

  执行生成后,会在控制台中显示最终的结果,如下图示:如果成功会显示 buid success,并会在相应的目录中生成对应的文件

  2.4 进阶用法:自定义 Mybatis Generator 的生成过程中的插件类,以便添加额外自定义的方法

  虽然使用Mybatis Generator减少了手工编写代码及 XML 的工作量,但由于生成的 CRUD 方法都是比较简单的,稍微复杂或灵活一点的方法都不能简单生成,如果单纯的在生成代码后再人工手动添加其它自定义的方法,又担心如果执行一次自动生成又会覆盖手动添加的自定义代码,那有没有办法解决呢?当然是有的,我(梦在旅途,zuowenjun.cn)在网络上了解到的方法大部份都是说获取Mybatis Generator源代码,然后进行二次开发,最后使用“定制版”的Mybatis Generator,我个人觉得虽然能解决问题,但如果能力不足,可能会出现意想不到的问题,而且进行定制也不是那么简单的,故我这里采取Mybatis Generator框架提供的可扩展插件 plugin 来实现扩展,具体步骤如下:

  2.4.1. 在项目新创建一个包 cn.zuowenjun.boot.mybatis.plugin, 然后在包里面先创建一个泛型通用插件基类(CustomAppendMethodPlugin),这个基类主要是用于附加自定义方法,故取名 CustomAppendMethodPlugin,代码如下:

package cn.zuowenjun.boot.mybatis.plugin;

import java.util.List;

import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.codegen.mybatis3.javamapper.elements.AbstractJavaMapperMethodGenerator;
import org.mybatis.generator.codegen.mybatis3.xmlmapper.elements.AbstractXmlElementGenerator;

/*

  • 自定义通用可添加生成自定义方法插件类

  • Author:zuowenjun

  • Date:2019-1-29
    */
    public abstract class CustomAppendMethodPlugin<TE extends AbstractXmlElementGenerator,TM extends AbstractJavaMapperMethodGenerator>
    extends PluginAdapter {

    protected final Class<TE> teClass;
    protected final Class<TM> tmClass;

    @SuppressWarnings("unchecked")
    public CustomAppendMethodPlugin(Class<? extends AbstractXmlElementGenerator> teClass,
    Class
    <? extends AbstractJavaMapperMethodGenerator> tmClass) {
    this.teClass=(Class<TE>) teClass;
    this.tmClass=(Class<TM>) tmClass;
    }

    @Override
    public boolean sqlMapDocumentGenerated(Document document,
    IntrospectedTable introspectedTable) {

         </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
             AbstractXmlElementGenerator elementGenerator </span>=<span style="color: rgba(0, 0, 0, 1)"> teClass.newInstance();
             elementGenerator.setContext(context);
             elementGenerator.setIntrospectedTable(introspectedTable);
             elementGenerator.addElements(document.getRootElement());
    
         } </span><span style="color: rgba(0, 0, 255, 1)">catch</span> (InstantiationException |<span style="color: rgba(0, 0, 0, 1)"> IllegalAccessException e) {
             </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO Auto-generated catch block</span>
    

e.printStackTrace();
}

    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.sqlMapDocumentGenerated(document, introspectedTable);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> clientGenerated(Interface interfaze,
        TopLevelClass topLevelClass,
        IntrospectedTable introspectedTable) {
    
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        AbstractJavaMapperMethodGenerator methodGenerator </span>=<span style="color: rgba(0, 0, 0, 1)"> tmClass.newInstance();
        methodGenerator.setContext(context);
        methodGenerator.setIntrospectedTable(introspectedTable);
        methodGenerator.addInterfaceElements(interfaze);
        
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span> (InstantiationException |<span style="color: rgba(0, 0, 0, 1)"> IllegalAccessException e) {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO Auto-generated catch block</span>

e.printStackTrace();
}

    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.clientGenerated(interfaze, topLevelClass, introspectedTable);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span> validate(List&lt;String&gt;<span style="color: rgba(0, 0, 0, 1)"> warnings) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO Auto-generated method stub</span>
    <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
}

}

View Code

  代码比较简单,主要是重写了 sqlMapDocumentGenerated(生成 mapper xml 方法)、clientGenerated(生成 mapper 接口方法),在这里面我通过把指定泛型类型(分别继承自 AbstractXmlElementGenerator、AbstractJavaMapperMethodGenerator)加入到生成 XML 和接口的过程中,以实现生成过程的抽象。

  2.4.2. 我这里由于默认生成的 ShoppingOrderDetailMapper(实体类:ShoppingOrderDetail 是购物订单详情)无法满足需要,我需要额外再增加两个方法:

  List<ShoppingOrderDetail> selectByOrderId(int shoppingOrderId); 、void deleteByOrderId(int shoppingOrderId); 故在这里自定义继承自 CustomAppendMethodPlugin 的插件类:ShoppingOrderDetailMapperPlugin,具体实现代码如下:

package cn.zuowenjun.boot.mybatis.plugin;

import java.util.Set;
import java.util.TreeSet;

import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.codegen.mybatis3.javamapper.elements.AbstractJavaMapperMethodGenerator;
import org.mybatis.generator.codegen.mybatis3.xmlmapper.elements.AbstractXmlElementGenerator;

/*

  • ref see https://www.cnblogs.com/se7end/p/9293755.html

  • Author:zuowenjun

  • Date:2019-1-29
    */
    public class ShoppingOrderDetailMapperPlugin
    extends CustomAppendMethodPlugin<ShoppingOrderDetailXmlElementGenerator, AbstractJavaMapperMethodGenerator> {

    public ShoppingOrderDetailMapperPlugin() {
    super(ShoppingOrderDetailXmlElementGenerator.class,ShoppingOrderDetailJavaMapperMethodGenerator.class);
    }

}

class ShoppingOrderDetailXmlElementGenerator extends AbstractXmlElementGenerator{

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> addElements(XmlElement parentElement) {
    
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(!introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime().equalsIgnoreCase("TA_TestShoppingOrderDetail"<span style="color: rgba(0, 0, 0, 1)">)) {
        </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
    }

    TextElement selectText </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> TextElement("select * from " +<span style="color: rgba(0, 0, 0, 1)"> introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime()
    </span>+ " where shoppingOrderId=#{shoppingOrderId}"<span style="color: rgba(0, 0, 0, 1)">);
    
     XmlElement selectByOrderId </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> XmlElement("select"<span style="color: rgba(0, 0, 0, 1)">);
     selectByOrderId.addAttribute(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Attribute("id", "selectByOrderId"<span style="color: rgba(0, 0, 0, 1)">));
     selectByOrderId.addAttribute(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Attribute("resultMap", "BaseResultMap"<span style="color: rgba(0, 0, 0, 1)">));
     selectByOrderId.addAttribute(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Attribute("parameterType", "int"<span style="color: rgba(0, 0, 0, 1)">));
     selectByOrderId.addElement(selectText);
     parentElement.addElement(selectByOrderId);
     
        TextElement deleteText </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> TextElement("delete from " +<span style="color: rgba(0, 0, 0, 1)"> introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime()
        </span>+ " where shoppingOrderId=#{shoppingOrderId}"<span style="color: rgba(0, 0, 0, 1)">);
        
         XmlElement deleteByOrderId </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> XmlElement("delete"<span style="color: rgba(0, 0, 0, 1)">);
         deleteByOrderId.addAttribute(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Attribute("id", "deleteByOrderId"<span style="color: rgba(0, 0, 0, 1)">));
         deleteByOrderId.addAttribute(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Attribute("parameterType", "int"<span style="color: rgba(0, 0, 0, 1)">));
         deleteByOrderId.addElement(deleteText);
         parentElement.addElement(deleteByOrderId);
}

}

class ShoppingOrderDetailJavaMapperMethodGenerator extends AbstractJavaMapperMethodGenerator{

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> addInterfaceElements(Interface interfaze) {
    
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(!introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime().equalsIgnoreCase("TA_TestShoppingOrderDetail"<span style="color: rgba(0, 0, 0, 1)">)) {
        </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
    }
    
    addInterfaceSelectByOrderId(interfaze);
    addInterfaceDeleteByOrderId(interfaze);
}

   </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> addInterfaceSelectByOrderId(Interface interfaze) {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 先创建import对象</span>
        Set&lt;FullyQualifiedJavaType&gt; importedTypes = <span style="color: rgba(0, 0, 255, 1)">new</span> TreeSet&lt;FullyQualifiedJavaType&gt;<span style="color: rgba(0, 0, 0, 1)">();
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 添加Lsit的包</span>

importedTypes.add(FullyQualifiedJavaType.getNewListInstance());
// 创建方法对象
Method method = new Method();
// 设置该方法为 public
method.setVisibility(JavaVisibility.PUBLIC);
// 设置返回类型是 List
FullyQualifiedJavaType returnType = FullyQualifiedJavaType.getNewListInstance();
FullyQualifiedJavaType listArgType
= new FullyQualifiedJavaType(introspectedTable.getBaseRecordType());
returnType.addTypeArgument(listArgType);

        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 方法对象设置返回类型对象</span>

method.setReturnType(returnType);
// 设置方法名称为我们在 IntrospectedTable 类中初始化的 “selectByOrderId”
method.setName("selectByOrderId");

        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 设置参数类型是int类型</span>

FullyQualifiedJavaType parameterType;
parameterType
= FullyQualifiedJavaType.getIntInstance();
// import 参数类型对象 (基本类型其实可以不必引入包名)
//importedTypes.add(parameterType);
// 为方法添加参数,变量名称 record
method.addParameter(new Parameter(parameterType, "shoppingOrderId")); //$NON-NLS-1$
//
context.getCommentGenerator().addGeneralMethodComment(method, introspectedTable);
if (context.getPlugins().clientSelectByPrimaryKeyMethodGenerated(method, interfaze, introspectedTable)) {
interfaze.addImportedTypes(importedTypes);
interfaze.addMethod(method);
}
}

   </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> addInterfaceDeleteByOrderId(Interface interfaze) {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建方法对象</span>
        Method method = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Method();
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 设置该方法为public</span>

method.setVisibility(JavaVisibility.PUBLIC);
// 设置方法名称为我们在 IntrospectedTable 类中初始化的 “deleteByOrderId”
method.setName("deleteByOrderId");
// 设置参数类型是 int 类型
FullyQualifiedJavaType parameterType;
parameterType
= FullyQualifiedJavaType.getIntInstance();
method.addParameter(
new Parameter(parameterType, "shoppingOrderId")); //$NON-NLS-1$

context.getCommentGenerator().addGeneralMethodComment(method, introspectedTable);
if (context.getPlugins().clientSelectByPrimaryKeyMethodGenerated(method, interfaze, introspectedTable)) {
interfaze.addMethod(method);
}

   }

}

从如上代码所示,核心点是自定义继承自 AbstractXmlElementGenerator、AbstractJavaMapperMethodGenerator 的 ShoppingOrderDetailXmlElementGenerator(XML 生成器类)、ShoppingOrderDetailJavaMapperMethodGenerator(mapper 接口生成器类),然后分别在 addElements、addInterfaceElements 添加自定义生成 XML 及接口方法的逻辑(如上代码中使用的是反射,若想学习了解反射请自行网上查找相关资料,C# 也有反射哦,应该好理解),注意由于插件在生成过程中每个实体类都会调用一次,故必需作相应的判断(判断当前要附加的自定义方法是符与当前实体类生成过程相符,如果不相符则忽略退出)

如下是 ShoppingOrderDetail 实体类的代码:

package cn.zuowenjun.boot.domain;

import java.math.BigDecimal;
import java.util.Date;

public class ShoppingOrderDetail {
private Integer id;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Integer shoppingorderid;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Integer goodsid;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Integer qty;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> BigDecimal totalprice;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String createby;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Date createtime;

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Integer getId() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setId(Integer id) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Integer getShoppingorderid() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> shoppingorderid;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setShoppingorderid(Integer shoppingorderid) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.shoppingorderid =<span style="color: rgba(0, 0, 0, 1)"> shoppingorderid;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Integer getGoodsid() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> goodsid;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setGoodsid(Integer goodsid) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.goodsid =<span style="color: rgba(0, 0, 0, 1)"> goodsid;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Integer getQty() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> qty;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setQty(Integer qty) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.qty =<span style="color: rgba(0, 0, 0, 1)"> qty;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> BigDecimal getTotalprice() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> totalprice;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setTotalprice(BigDecimal totalprice) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.totalprice =<span style="color: rgba(0, 0, 0, 1)"> totalprice;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getCreateby() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> createby;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setCreateby(String createby) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.createby = createby == <span style="color: rgba(0, 0, 255, 1)">null</span> ? <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)"> : createby.trim();
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Date getCreatetime() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> createtime;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setCreatetime(Date createtime) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.createtime =<span style="color: rgba(0, 0, 0, 1)"> createtime;
}

}

View Code

另外顺便解决一个踩坑点:上面提到了,我们在 POM 文件配置 mybatis-generator-maven-plugin 插件时,overwrite 设为 true,目的是确保每次执行生成时,生成的代码能够覆盖已经存在的,理想是美好的,但现实总会有点小意外,我们这样配置,只能解决生成的 mapper 接口类文件不会重复,但生成的 mapper xml 文件仍然会附加代码导致重复,故我们需要解决这个问题,而解决这个问题的关键是:GeneratedXmlFile.isMergeable,如果 isMergeable 为 true 则会合并,目前默认都是 false,所以我们只需实现将 GeneratedXmlFile.isMergeable 设为 true 即可,由于 isMergeable 是私有字段,只能采取插件 + 反射动态改变这个值了,自定义合并代码插件 OverIsMergeablePlugin 实现如下:

package cn.zuowenjun.boot.mybatis.plugin;

import java.lang.reflect.Field;
import java.util.List;

import org.mybatis.generator.api.GeneratedXmlFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;

/*

  • 修复 mybatis-generator 重复执行时生成的 XML 有重复代码 (核心:isMergeable=false)

  • Author:https://blog.csdn.net/zengqiang1/article/details/79381418

  • Editor:zuowenjun
    */
    public class OverIsMergeablePlugin extends PluginAdapter {

    @Override
    public boolean validate(List<String> warnings) {
    return true;
    }

    @Override
    public boolean sqlMapGenerated(GeneratedXmlFile sqlMap,
    IntrospectedTable introspectedTable) {

       </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
           Field field </span>= sqlMap.getClass().getDeclaredField("isMergeable"<span style="color: rgba(0, 0, 0, 1)">);
           field.setAccessible(</span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
           field.setBoolean(sqlMap, </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
       } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
           e.printStackTrace();
       }
    
     </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
    

    }

}

2.4.3. 在 generatorconfig.xml 配置文件中增加 plugin 配置,如下:

        <plugin type="cn.zuowenjun.boot.mybatis.plugin.OverIsMergeablePlugin"></plugin>
        <plugin type="cn.zuowenjun.boot.mybatis.plugin.ShoppingOrderDetailMapperPlugin"></plugin>

... ... 省略中间过程

    </span><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">table </span><span style="color: rgba(255, 0, 0, 1)">tableName</span><span style="color: rgba(0, 0, 255, 1)">="TA_TestShoppingOrderDetail"</span><span style="color: rgba(255, 0, 0, 1)">
        domainObjectName</span><span style="color: rgba(0, 0, 255, 1)">="ShoppingOrderDetail"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">generatedKey </span><span style="color: rgba(255, 0, 0, 1)">column</span><span style="color: rgba(0, 0, 255, 1)">="id"</span><span style="color: rgba(255, 0, 0, 1)"> sqlStatement</span><span style="color: rgba(0, 0, 255, 1)">="JDBC"</span><span style="color: rgba(255, 0, 0, 1)"> identity</span><span style="color: rgba(0, 0, 255, 1)">="true"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">table</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>

2.4.4. 由于不能在同一个项目中直接使用 plugin 类(具体原因请上网查询,在此了解即可),故还需把 cn.zuowenjun.boot.mybatis.plugin 这个包中的文件单独导出生成 JAR 包,然后把这个 JAR 包复制到项目的指定目录下(本示例是放在 libs 目录下),然后再在 POM 为 mybatis-generator-maven-plugin 单独添加 system 本地依赖才行,maven 添加依赖如下:

            <plugin>
                <!--ref: https://gitee.com/free/Mybatis_Utils/blob/master/MybatisGeneator/MybatisGeneator.md -->
                <!--ref: https://www.cnblogs.com/handsomeye/p/6268513.html -->
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.7</version>
                <configuration>
                    <configurationFile>src/main/resources/mybatis/generatorconfig.xml</configurationFile>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
                <dependencies>
                    <!-- 为 mybatis-generator 增加自定义插件依赖 -->
                    <dependency>
                        <groupId>cn.zuowenjun.boot.mybatis.plugin</groupId>
                        <artifactId>cn.zuowenjun.boot.mybatis.plugin</artifactId>
                        <version>1.0</version>
                        <scope>system</scope>
                        <systemPath>${basedir}/src/main/libs/cn.zuowenjun.boot.mybatis.plugin.jar</systemPath>
                    </dependency>
                </dependencies>
            </plugin>

如果 4 步完成后,最后执行 maven buid 的生成 mybatis 代码过程即可,最后查看生成的 mapper 及 xml 都会有对应的自定义方法,在此就不再贴出结果了。

  2.5 进阶用法:利用 Mybatis 的继承机制实现添加额外自定义方法

  如 2.4 节所述,我们可以通过自定义 plugin 来实现添加额外自定义的方法,而且不用担心被覆盖,但可能实现有点麻烦(里面用到了反射),有没有简单一点的办法呢?当然有,即可以先使用Mybatis Generator框架生成默代代码,然后再结合使用 2.2 所述方法(手写 mapper 接口类及 mapper XML),利用 mapper XML 的继承特性完成添加自定义方法的过程中,具体步骤与 2.2 相同,在此贴出(注意前提是先自动生成代码,然后再操作如下步骤)

  2.5.1. 定义扩展 mapper 接口类(ShoppingOrderExtMapper,扩展 ShoppingOrderMapper,它们之间无需继承),代码如下:(很简单,就是定义了一个特殊用途的方法)

package cn.zuowenjun.boot.mapper;

import java.util.List;

import cn.zuowenjun.boot.domain.ShoppingOrder;

public interface ShoppingOrderExtMapper {

List</span>&lt;ShoppingOrder&gt;<span style="color: rgba(0, 0, 0, 1)"> selectAllByShopper(String shopper);

}

  2.5.2. 编写对应的 ShoppingOrderExtMapper.xml,这里面就要用到继承,继承主要是 resultMap【实现继承用:extends= 要继承的 mapper xml resultMap】,这样就不用两个地方都为一个实体类写结果映射配置了,其余的都按一个新的 mapper XML 配置来设计即可,代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.zuowenjun.boot.mapper.ShoppingOrderExtMapper">
    <resultMap id="BaseResultMap" type="cn.zuowenjun.boot.domain.ShoppingOrder" 
    extends="cn.zuowenjun.boot.mapper.ShoppingOrderMapper.BaseResultMap">
    </resultMap>
    <select id="selectAllByShopper" resultMap="BaseResultMap" parameterType="string">
        select * from TA_TestShoppingOrder where shopper=#{shopper}
    </select>
</mapper>

如上两步即完成扩展添加额外自定义的方法,又不用担心重复执行生成代码会被覆盖掉,只是使用时需要单独注册到 spring,单独实例,虽不完美但弥补了默认生成代码的不足也是可行的。

  2.6 使用 SpringBootTest + junit 测试基于 Mybatis 框架实现的 DAO 类

   在此不详情说明 junit 测试的用法,网上大把资源,只是单独说明结合SpringBootTest 注解,完成单元测试,先看单元测试代码:

package cn.zuowenjun.springbootdemo;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import cn.zuowenjun.boot.SpringbootdemoApplication;
import cn.zuowenjun.boot.domain.*;
import cn.zuowenjun.boot.mapper.GoodsMapper;
import cn.zuowenjun.boot.mapper.ShoppingOrderDetailMapper;
import cn.zuowenjun.boot.mapper.ShoppingOrderMapper;

@RunWith(SpringRunner.class)
@SpringBootTest(classes
=SpringbootdemoApplication.class)
public class ShoppingOrderMapperTests {

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> ShoppingOrderMapper shoppingOrderMapper;

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> ShoppingOrderDetailMapper shoppingOrderDetailMapper;

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> GoodsMapper goodsMapper;

@Transactional
@Rollback(</span><span style="color: rgba(0, 0, 255, 1)">false</span>) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">不加这个,默认测试完后自动回滚</span>

@Test
public void testInsertShoppingOrder() {

    Goods goods</span>= goodsMapper.get(1<span style="color: rgba(0, 0, 0, 1)">);
    
    ShoppingOrder shoppingOrder</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ShoppingOrder();
    shoppingOrder.setShopper(</span>"zuowenjun"<span style="color: rgba(0, 0, 0, 1)">);
    shoppingOrder.setIscompleted(</span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
    shoppingOrder.setTotalprice(BigDecimal.valueOf(</span>0<span style="color: rgba(0, 0, 0, 1)">));
    shoppingOrder.setTotalqty(</span>1<span style="color: rgba(0, 0, 0, 1)">);
    shoppingOrder.setCreateby(</span>"zuowenjun"<span style="color: rgba(0, 0, 0, 1)">);
    shoppingOrder.setCreatetime(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date());
    
    </span><span style="color: rgba(0, 0, 255, 1)">int</span> orderId=<span style="color: rgba(0, 0, 0, 1)"> shoppingOrderMapper.insert(shoppingOrder);
    shoppingOrder.setId(orderId);
    
    ShoppingOrderDetail shoppingOrderDetail</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ShoppingOrderDetail();
    shoppingOrderDetail.setGoodsid(goods.getId());
    shoppingOrderDetail.setShoppingorderid(shoppingOrder.getId());
    shoppingOrderDetail.setQty(</span>10<span style="color: rgba(0, 0, 0, 1)">);
    shoppingOrderDetail.setTotalprice(BigDecimal.valueOf(shoppingOrderDetail.getQty()).multiply(goods.getPrice()));
    shoppingOrderDetail.setCreateby(</span>"zuowenjun"<span style="color: rgba(0, 0, 0, 1)">);
    shoppingOrderDetail.setCreatetime(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date());
    
    shoppingOrderDetailMapper.insert(shoppingOrderDetail);
    
    List</span>&lt;ShoppingOrderDetail&gt; orderDetails=<span style="color: rgba(0, 0, 0, 1)"> shoppingOrderDetailMapper.selectByOrderId(shoppingOrder.getId());
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(orderDetails!=<span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; orderDetails.size()&gt;0<span style="color: rgba(0, 0, 0, 1)">) {
        </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)">(ShoppingOrderDetail od:orderDetails) {
            System.out.println(</span>"id:" + od.getId() + ",goodsid:" +<span style="color: rgba(0, 0, 0, 1)"> od.getGoodsid());
        }
    }
    
    Assert.assertTrue(orderDetails.size()</span>&gt;0<span style="color: rgba(0, 0, 0, 1)">); 
}

}

View Code

  与 Junit 单元测试用法基本相同,唯 一的区别就是在单元测试的类上添加 @SpringBootTest,并指定启动类(如代码中所示:@SpringBootTest(classes=SpringbootdemoApplication.class)),另外注意一点:如果测试方法使用 @Transactional 注解,那么当测试完成后会回滚(即并不会提交事务),如果想完成事务的提交,则需如代码中所示添加 @Rollback(false),其中 false 指不回滚,true 则为回滚。

三、简单演示集成 Thymeleaf 模板引擎(这里只是用一个简单的页面演示效果,由于现在都流行前后端分离,故只需了解即可)

  说明:Thymeleaf 是 spring MVC 的端视图引擎,与 JSP 视图引擎类似,只不过在 spring boot 项目中默认支持 Thymeleaf(Thymeleaf 最大的优点是视图中不含 JAVA 代码,不影响 UI 美工及前端设计),而 JSP 不建议使用,当然也可以通过添加相关的 JSP 的 JAR 包依赖,实现 JSP 视图,具体请自行网上查找资源,同时 spring MVC +JSP 视图的用法可以参见该系列的上篇文章

  3.1. 添加 Thymeleaf 的 maven 依赖,POM 配置如下:

        <!-- 添加 thymeleaf 模板引擎(用于 springMVC 模式,如果是 rest API 项目,则无需引用) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

  3.2. 编写后端 controller,以便响应用户请求,代码如下:(这个与普通 spring MVC+JSP 相同,区别在 VIEW)

package cn.zuowenjun.boot.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import cn.zuowenjun.boot.domain.;
import cn.zuowenjun.boot.service.
;

@Controller
@RequestMapping("/test")
public class TestController {

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> ShopUserService shopUserService;

@GetMapping(</span>"/userlist"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String list(Model model) {
    
    List</span>&lt;ShopUser&gt; users=<span style="color: rgba(0, 0, 0, 1)"> shopUserService.getAll();
    model.addAttribute(</span>"title", "测试使用thymeleaf模板引擎展示数据"<span style="color: rgba(0, 0, 0, 1)">);
    model.addAttribute(</span>"users"<span style="color: rgba(0, 0, 0, 1)">, users);
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">可以在application.properties添加如下配置,以改变thymeleaf的默认设置
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">spring.thymeleaf.prefix="classpath:/templates/" 模板查找路径
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">spring.thymeleaf.suffix=".html" 模板后缀名</span>
    
    <span style="color: rgba(0, 0, 255, 1)">return</span> "/test";<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">默认自动查找路径:src/main/resources/templates/*.html</span>

}
}

  3.3 编写前端视图 html 模板页面,最后演示效果

   HTML 视图页面代码:(th:XXX 为 Thymeleaf 的模板特有的标识符,${xxx} 这是 SP EL 表达式,这个之前讲过的,很简单,不展开说明)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>test User List -power by thymeleaf</title>
<style type="text/css">
    table{
        border:2px solid blue;
        border-collapse:collapse;
        width:98%;
    }
table *</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)">
    border</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">1px solid blue</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)">
    text-align</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">center</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">}</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(128, 0, 0, 1)">

thead</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)">
    background-color</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">purple</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)">
    color</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">yellow</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">}</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(128, 0, 0, 1)">

th,td</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)">
    padding</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">5px</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">}</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(128, 0, 0, 1)">

#copy</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)">
    margin-top</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">100px</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)">
    text-align</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> center</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">}</span>

</style>
</head>
<body>
<h1 th:text="${title}"></h1>
<table>
<thead>
<tr>
<th>SeqNo</th>
<th>userId</th>
<th>nickName</th>
<th>depositAmount</th>
</tr>
</thead>
<tbody>
<tr th:if="${users}!=null" th:each="user,iterStat:${users}">
<td th:text="${iterStat.index}+1">1</td>
<td th:text="${user.userid}">www.zuowenjun.cn</td>
<td th:text="${user.nickname}">梦在旅途</td>
<td th:text="${user.depositamount}">520</td>
</tr>
<tr th:unless="${users.size()} gt 0">
<td colspan="4">暂无相关记录!</td>
</tr>
</tbody>
</table>
<p id="copy">
Copyright
&copy;<span th:text="${#dates.format(#dates.createToday(),'yyyy')}"></span>
www.zuowenjun.cn and zuowj.cnblogs.com demo all rights.
</p>
</body>
</html>

View Code

最后浏览:http://localhost:8080/test/userlist,效果如下图示:

四、利用 VUE+SpringMVC Rest API 编写实现前后端分离的电商购物 Demo(浏览商品、添加购物车、下单、完成)

说明:由于数据访问层(或称:数据持久层)已由Mybatis Generator完成了,现在就只要编写业务领域服务层(接口层、实现层),API 接入层即可完成后端开发,然后再开发设计前端页面即可(前端与后端交互使用 AJAX)

  4.1. 在 cn.zuowenjun.boot.service 包中定义相关的业务领域服务接口

//ShopUserService.java

package cn.zuowenjun.boot.service;

import java.util.List;

import cn.zuowenjun.boot.domain.ShopUser;

public interface ShopUserService {

List</span>&lt;ShopUser&gt;<span style="color: rgba(0, 0, 0, 1)"> getAll();

ShopUser get(String userId);

String getCurrentLoginUser();

String login(String uid,String pwd);

</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> logout();

}

//GoodsService.java
package cn.zuowenjun.boot.service;

import java.util.List;

import org.springframework.web.multipart.MultipartFile;

import cn.zuowenjun.boot.domain.*;

public interface GoodsService {

List</span>&lt;Goods&gt; getGoodsListByPage(<span style="color: rgba(0, 0, 255, 1)">int</span> pageSize,<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> pageNo);

List</span>&lt;Goods&gt; getGoodsListByCategory(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> categoryId);

List</span>&lt;Goods&gt; getGoodsListByMultIds(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">...goodsIds);

Goods getGoods(</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id);

</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> insertGoods(Goods goods,MultipartFile uploadGoodsPic);

</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> updateGoods(Goods goods,MultipartFile uploadGoodsPic);

</span><span style="color: rgba(0, 0, 255, 1)">void</span> deleteGoods(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id);

List</span>&lt;GoodsCategory&gt;<span style="color: rgba(0, 0, 0, 1)"> getAllGoodsCategoryList();

</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> insertGoodsCategory(GoodsCategory goodsCategory);

</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> updateGoodsCategory(GoodsCategory goodsCategory);

</span><span style="color: rgba(0, 0, 255, 1)">void</span> deleteGoodsCategory(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id);

}

//ShoppingOrderService.java
package cn.zuowenjun.boot.service;

import java.util.List;

import cn.zuowenjun.boot.domain.*;

public interface ShoppingOrderService {

ShoppingOrder getShoppingOrder(</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id);

List</span>&lt;ShoppingOrder&gt;<span style="color: rgba(0, 0, 0, 1)"> getShoppingOrderList(String shopper);

List</span>&lt;ShoppingOrderDetail&gt; getShoppingOrderDetail(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> orderId);

</span><span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> createShoppingOrderByShopper(String shopper);

</span><span style="color: rgba(0, 0, 255, 1)">void</span> insertShoppingOrderWithDetail(ShoppingOrder order,List&lt;ShoppingOrderDetail&gt;<span style="color: rgba(0, 0, 0, 1)"> orderDetails);

</span><span style="color: rgba(0, 0, 255, 1)">void</span> deleteShoppingOrderDetail(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> orderDetailId);

</span><span style="color: rgba(0, 0, 255, 1)">void</span> deleteShoppingOrderWithDetail(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> orderId);

</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> updateShoppingOrder(ShoppingOrder order);

List</span>&lt;ShoppingCart&gt;<span style="color: rgba(0, 0, 0, 1)"> getShoppingCartList(String shopper);

</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getShoppingCartBuyCount(String shopper);

</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> insertShoppingCart(ShoppingCart shoppingCart);

</span><span style="color: rgba(0, 0, 255, 1)">void</span> deleteShoppingCart(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> shoppingCartId);

</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> clearShoppingCart(String shopper);

}

View Code

  如上代码示,我仅定义了三个 service 接口,分别是:ShopUserService(用户服务)、GoodsService(商品服务【含:商品类别、商品信息】)、ShoppingOrderService(购物订单服务【含:购物车、购物订单、购物订单明细】),我说过服务层不一定是与 DB 中的表一 一对应的,而是应该体现服务内聚(即:业务领域),如果单纯的与 DAO 层一样,一个 service 与一个 dao 对应,那就失去了分层的意义,而且还增加了复杂度。个人看法。

  4.2 在 cn.zuowenjun.boot.service.impl 包中实现 4.1 中相关的业务领域服务接口(代码很简单,主要是实现接口的一些方法,唯一有点特别是文件上传,事务,记录日志,这些通过代码就能看明白就不再详情描述了)

//ShopUserServiceImpl.java
package cn.zuowenjun.boot.service.impl;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import cn.zuowenjun.boot.EShopProperties;
import cn.zuowenjun.boot.domain.ShopUser;
import cn.zuowenjun.boot.mapper.ShopUserMapper;
import cn.zuowenjun.boot.service.ShopUserService;

@Service
public class ShopUserServiceImpl implements ShopUserService {

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> ShopUserMapper shopUserMapper;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> EShopProperties shopProperties;

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> ShopUserServiceImpl(ShopUserMapper shopUserMapper,EShopProperties shopProperties) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.shopUserMapper=<span style="color: rgba(0, 0, 0, 1)">shopUserMapper;
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.shopProperties=<span style="color: rgba(0, 0, 0, 1)">shopProperties;
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;ShopUser&gt;<span style="color: rgba(0, 0, 0, 1)"> getAll() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> shopUserMapper.selectAll();
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> ShopUser get(String userId) {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> shopUserMapper.selectByPrimaryKey(userId);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getCurrentLoginUser() {
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(getRequest().getSession().getAttribute("loginUser")==<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
        </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    }
    
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> getRequest().getSession().getAttribute("loginUser"<span style="color: rgba(0, 0, 0, 1)">).toString();
    
}


@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String login(String uid, String pwd) {
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(shopProperties.getShopUserId().equalsIgnoreCase(uid) &amp;&amp;<span style="color: rgba(0, 0, 0, 1)"> 
            shopProperties.getShopUserPwd().equals(pwd)) {
        getRequest().getSession().setAttribute(</span>"loginUser"<span style="color: rgba(0, 0, 0, 1)">, uid);
        </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
        </span><span style="color: rgba(0, 0, 255, 1)">return</span> "用户名或密码不正确!"<span style="color: rgba(0, 0, 0, 1)">;
    }
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> logout() {
    getRequest().getSession().removeAttribute(</span>"loginUser"<span style="color: rgba(0, 0, 0, 1)">);
}


</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> HttpServletRequest getRequest() {
    HttpServletRequest  request</span>=<span style="color: rgba(0, 0, 0, 1)"> ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> request;
}

}

//GoodsServiceImpl.java
package cn.zuowenjun.boot.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import cn.zuowenjun.boot.domain.*;
import cn.zuowenjun.boot.mapper.GoodsCategoryMapper;
import cn.zuowenjun.boot.mapper.GoodsMapper;
import cn.zuowenjun.boot.service.GoodsService;

@Service
public class GoodsServiceImpl implements GoodsService {

</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> Logger logger=LoggerFactory.getLogger(GoodsServiceImpl.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> GoodsMapper goodsMapper;

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> GoodsCategoryMapper categoryMapper;

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;Goods&gt; getGoodsListByPage(<span style="color: rgba(0, 0, 255, 1)">int</span> pageSize,<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> pageNo){
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> goodsMapper.getListByPage(pageSize, pageNo);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;Goods&gt; getGoodsListByCategory(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> categoryId) {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> goodsMapper.getList(categoryId);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;Goods&gt; getGoodsListByMultIds(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">... goodsIds) {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> goodsMapper.getListByMultIds(goodsIds);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> Goods getGoods(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> goodsMapper.get(id);
}

@Transactional
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> insertGoods(Goods goods, MultipartFile uploadGoodsPic) {
    String picPath</span>=<span style="color: rgba(0, 0, 0, 1)"> saveGoodsPic(uploadGoodsPic);
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(picPath!=<span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; !<span style="color: rgba(0, 0, 0, 1)">picPath.isEmpty()) {
        
        goods.setPicture(picPath);
    }
    goodsMapper.insert(goods);
    
    GoodsCategory gcate</span>=<span style="color: rgba(0, 0, 0, 1)"> categoryMapper.get(goods.getCategoryId());
    gcate.setGoodsCount(gcate.getGoodsCount()</span>+1<span style="color: rgba(0, 0, 0, 1)">);
    categoryMapper.update(gcate);
    
    logger.info(</span>"inserted new goods - id:" +<span style="color: rgba(0, 0, 0, 1)"> goods.getId());
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> updateGoods(Goods goods,MultipartFile uploadGoodsPic) {
    String picPath</span>=<span style="color: rgba(0, 0, 0, 1)"> saveGoodsPic(uploadGoodsPic);
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(picPath!=<span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; !<span style="color: rgba(0, 0, 0, 1)">picPath.isEmpty()) {
        
        goods.setPicture(picPath);
    }
     goodsMapper.update(goods);
     
     logger.info(</span>"update goods - id:" +<span style="color: rgba(0, 0, 0, 1)"> goods.getId());
}

@Transactional
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> deleteGoods(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) {
    Goods g</span>=<span style="color: rgba(0, 0, 0, 1)"> goodsMapper.get(id);
    goodsMapper.delete(g.getId());
    
    GoodsCategory gcate</span>=<span style="color: rgba(0, 0, 0, 1)"> categoryMapper.get(g.getCategoryId());
    gcate.setGoodsCount(gcate.getGoodsCount()</span>-1<span style="color: rgba(0, 0, 0, 1)">);
    categoryMapper.update(gcate);
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果有图片,则同时删除图片</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span>(g.getPicture()!=<span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; !<span style="color: rgba(0, 0, 0, 1)">g.getPicture().isEmpty()) {
        
        String picPath</span>= getRequest().getServletContext().getRealPath("/") +<span style="color: rgba(0, 0, 0, 1)"> g.getPicture();
        File file </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> File(picPath);
        </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(file.exists()) {
            file.delete();
        }
    }
    
    logger.info(</span>"deleted goods - id:" +<span style="color: rgba(0, 0, 0, 1)"> g.getId());
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;GoodsCategory&gt;<span style="color: rgba(0, 0, 0, 1)"> getAllGoodsCategoryList(){
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> categoryMapper.getAll();
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> insertGoodsCategory(GoodsCategory goodsCategory) {
    categoryMapper.insert(goodsCategory);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> updateGoodsCategory(GoodsCategory goodsCategory) {
    categoryMapper.update(goodsCategory);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> deleteGoodsCategory(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) {
    categoryMapper.delete(id);
}


</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String saveGoodsPic(MultipartFile uploadGoodsPic) {
    
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(uploadGoodsPic==<span style="color: rgba(0, 0, 255, 1)">null</span> ||<span style="color: rgba(0, 0, 0, 1)"> uploadGoodsPic.isEmpty()) {
        </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    }
    
    String fileName </span>=<span style="color: rgba(0, 0, 0, 1)"> uploadGoodsPic.getOriginalFilename();
    
    String extName </span>= fileName.substring(fileName.lastIndexOf("."<span style="color: rgba(0, 0, 0, 1)">));
    
    String newFileName</span>=UUID.randomUUID().toString()+<span style="color: rgba(0, 0, 0, 1)">extName;
    File file </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> File(getFileSavePath(newFileName));
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(!<span style="color: rgba(0, 0, 0, 1)">file.exists()) {
        file.getParentFile().mkdirs();
    }
    
    
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        uploadGoodsPic.transferTo(file);
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">return file.toURI().toURL().toString();</span>
        <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> getUrlPath(file.getAbsolutePath());
        
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IllegalStateException e) {
        e.printStackTrace();
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
        e.printStackTrace();
    }
    
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
}



</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String getFileSavePath(String fileName) {
    String realPath </span>=getRequest().getServletContext().getRealPath("/uploadimgs/"<span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> realPath +<span style="color: rgba(0, 0, 0, 1)"> fileName;
}

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String getUrlPath(String filePath) {
    String rootPath</span>= getRequest().getServletContext().getRealPath("/"<span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> filePath.replace(rootPath, "").replaceAll("\\\\", "/"<span style="color: rgba(0, 0, 0, 1)">);
}

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> HttpServletRequest getRequest() {
    HttpServletRequest  request</span>=<span style="color: rgba(0, 0, 0, 1)"> ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> request;
}

}

//ShoppingOrderServiceImpl.java
package cn.zuowenjun.boot.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.zuowenjun.boot.domain.;
import cn.zuowenjun.boot.mapper.
;
import cn.zuowenjun.boot.service.ShoppingOrderService;

@Service
public class ShoppingOrderServiceImpl implements ShoppingOrderService {

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> ShoppingOrderMapper  orderMapper;

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> ShoppingOrderDetailMapper orderDetailMapper;

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> ShoppingCartMapper shoppingCartMapper;

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> ShoppingOrderExtMapper shoppingOrderExtMapper;

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> insertShoppingCart(ShoppingCart shoppingCart) {
    ShoppingCart cart</span>=<span style="color: rgba(0, 0, 0, 1)">shoppingCartMapper.get(shoppingCart.getShopper(), shoppingCart.getGoodsId());
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(cart==<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
        shoppingCartMapper.insert(shoppingCart);
    }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
        cart.setQty(cart.getQty()</span>+<span style="color: rgba(0, 0, 0, 1)">shoppingCart.getQty());
        shoppingCartMapper.update(cart);
    }
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> deleteShoppingCart(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> shoppingCartId) {
    shoppingCartMapper.deleteItem(shoppingCartId);
}


@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> ShoppingOrder getShoppingOrder(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> orderMapper.selectByPrimaryKey(id);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;ShoppingOrder&gt;<span style="color: rgba(0, 0, 0, 1)"> getShoppingOrderList(String shopper) {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> shoppingOrderExtMapper.selectAllByShopper(shopper);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;ShoppingOrderDetail&gt; getShoppingOrderDetail(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> orderId) {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> orderDetailMapper.selectByOrderId(orderId);
}

@Transactional
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> createShoppingOrderByShopper(String shopper) {
    
    List</span>&lt;ShoppingCart&gt; carts=<span style="color: rgba(0, 0, 0, 1)"> shoppingCartMapper.getList(shopper);
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(carts==<span style="color: rgba(0, 0, 255, 1)">null</span> || carts.size()&lt;=0<span style="color: rgba(0, 0, 0, 1)">) {
        </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
    }
    
    </span><span style="color: rgba(0, 0, 255, 1)">int</span> totalQty=0<span style="color: rgba(0, 0, 0, 1)">;
    BigDecimal totalPrc</span>=BigDecimal.valueOf(0<span style="color: rgba(0, 0, 0, 1)">);
    List</span>&lt;ShoppingOrderDetail&gt; orderDetails=<span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">();
    
    </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)">(ShoppingCart c:carts) {
        totalQty</span>+=<span style="color: rgba(0, 0, 0, 1)">c.getQty();
        BigDecimal itemPrc</span>=<span style="color: rgba(0, 0, 0, 1)">c.getInGoods().getPrice().multiply(BigDecimal.valueOf(c.getQty()));
        totalPrc</span>=<span style="color: rgba(0, 0, 0, 1)">totalPrc.add(itemPrc);
        ShoppingOrderDetail od</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ShoppingOrderDetail();
        od.setGoodsid(c.getGoodsId());
        od.setQty(c.getQty());
        od.setTotalprice(itemPrc);
        od.setCreateby(shopper);
        od.setCreatetime(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date());
        
        orderDetails.add(od);
    }
    
    ShoppingOrder order</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ShoppingOrder();
    order.setShopper(shopper);
    order.setTotalqty(totalQty);
    order.setTotalprice(totalPrc);
    order.setCreateby(shopper);
    order.setCreatetime(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date());
    order.setIscompleted(</span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
    
    insertShoppingOrderWithDetail(order,orderDetails);
    
    clearShoppingCart(shopper);
    
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
}

@Transactional
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> insertShoppingOrderWithDetail(ShoppingOrder order, List&lt;ShoppingOrderDetail&gt;<span style="color: rgba(0, 0, 0, 1)"> orderDetails) {
    
    orderMapper.insert(order);
    </span><span style="color: rgba(0, 0, 255, 1)">int</span> orderId=<span style="color: rgba(0, 0, 0, 1)">order.getId();
    </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)">(ShoppingOrderDetail od:orderDetails) {
        od.setShoppingorderid(orderId);
        orderDetailMapper.insert(od);
    }
}


@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> deleteShoppingOrderDetail(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> orderDetailId) {
    
    orderDetailMapper.deleteByPrimaryKey(orderDetailId);
}

@Transactional
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> deleteShoppingOrderWithDetail(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> orderId) {
    
    orderMapper.deleteByPrimaryKey(orderId);
    orderDetailMapper.deleteByOrderId(orderId);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> updateShoppingOrder(ShoppingOrder order) {
    orderMapper.updateByPrimaryKey(order);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;ShoppingCart&gt;<span style="color: rgba(0, 0, 0, 1)"> getShoppingCartList(String shopper) {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> shoppingCartMapper.getList(shopper);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getShoppingCartBuyCount(String shopper) {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> shoppingCartMapper.getBuyCount(shopper);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> clearShoppingCart(String shopper) {
    shoppingCartMapper.delete(shopper);
}

}

View Code

  4.3 编写基于 VUE 前端框架实现的相关 UI 界面

  4.3.1.VUE 是什么?如何使用 VUE 前端框架设计页面?认真阅读官方中文教程就可以了:https://cn.vuejs.org/v2/guide/index.html ,这里只是着重说明一下,VUE 是实现了 MVVM 框架,使用 VUE 的核心组件:模板、路由、数据双向绑定等特性能够设计出很牛逼的 SPA(单 WEB 页面的多 UI 交互的应用),本人(梦在旅途)VUE 只是初学者,故在本示例中我只是使用 VUE 的最基本的一些功能属性(如:el:指定 VUE 的渲染范围(绑定的作用域)、data(数据模型 MODEL)、computed(动态计算属性)、created(VUE 初始化后触发的事件)、methods(绑定自定义方法))

  4.3.2. 由于采用前后端分离,完全可以一个项目全是静态的 VUE HTML 模板,另一个项目是基于 spring boot REST Api 项目,但这里是演示,故采取在同一个项目中,我这里是在 webapp 目录下创建相关的 HTML 视图页面,如果不在同一个项目中,注意基于 spring boot REST Api 项目中需要设置能够允许跨域访问,所有 HTML 视图代码如下:

index.html(商品列表,主页)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>梦在旅途的电商小店 Demo-Power by Spring Boot+MyBatis-Boot</title>
<meta name="author" content="www.zuowenjun.cn" >
<script src="https://cdn.jsdelivr.net/npm/vue" type="text/javascript"></script>
<script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>
<style type="text/css">
    #catesbox ul li{float:left;padding:5px;margin-right:20px;border:1px solid green;display: inline-block;cursor:pointer;}
    .clfx {clear:both;display:block;}
    .gpic{width:100px;height:100px;text-align:center;vertical-align:middle;}
    #goodsbox table {width:100%;border-collapse:collapse;}
    #goodsbox table tr >*{border:1px solid blue;padding:5px;}
    li.active{background-color:orange;font-weight:bold;}
    #copy{
        margin-top:20px;
        text-align: center;
    }
    body{padding-top:51px;}
    #topbar{height:50px;line-height:50px;margin:0;width:100%;background-color:WhiteSmoke;
        position: fixed;top:0;border-bottom:1px solid darkgray;text-align: right;}
</style>
</head>
<body>
<div id="app">
        <div id="topbar">
        <a href="/cartlist.html" target="_blank">购物车 (已加入商品数量:{{cartCount}})</a>&nbsp;|&nbsp;
        <a href="/orderlist.html" target="_blank">订单中心</a>&nbsp;|&nbsp;
        <a href="/admin.html" target="_blank">管理后台</a>&nbsp;&nbsp;&nbsp;&nbsp;
        </div>
        <h2>商品类目:</h2>
        <div id="catesbox">
            <ul v-for="c in cates">
                <li v-on:click="getGoodsListByCategory(c)" v-bind:class="{active:c.categoryName==curcate}">{{c.categoryName}}({{c.goodsCount}})</li>
            </ul>
            <div class="clfx"></div>
        </div>
    <h2>当前浏览的商品分类:<span>{{curcate}}</span></h2>
        <div id="goodsbox">
            <table>
                <tr>
                    <th>商品图片</th>
                    <th>商品标题</th>
                    <th>价格</th>
                    <th>操作</th>
                </tr>
                <tr v-for="g in goods">
                    <td><img v-bind:src="g.picture" class="gpic"></td>
                    <td><a v-bind:href="'/detail.html?gid=' + g.id" target="_blank">{{g.title}}</a></td>
                    <td>¥{{g.price}}</td>
                    <td><button v-on:click="addToShoppingCart(g)">加入购物车</button></td>
                </tr>
            </table>
        </div>
</div>
    <p id="copy">
    Copyright &copy;2019 &nbsp;
    www.zuowenjun.cn and zuowj.cnblogs.com demo all rights.
    </p>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                cartCount:0,
                cates:[],
                goods:[],
                curcate:"ALL"
            },
            created:function(){
                var self = this;
                 this.$http.get('/api/categorys').then(function(res){
                     self.cates=res.body;  
                     //alert(JSON.stringify(self.cates));
                    },function(){
                        alert("获取 categorys 失败!");});
             </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$http.get(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/api/cartlist</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">).then(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res){
                 self.cartCount</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">res.body.length;  
                 </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">alert(JSON.stringify(self.goods));</span>

},function(){
alert(
"获取购物车信息失败!");
});

            </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">按分页检索商品列表</span>
             <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.getGoodsListByPage(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">10</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">,</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">1</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
        },
        methods:{
            getGoodsListByCategory:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(cate){
                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> self </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;
                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">按类别检索商品列表</span>
                 <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$http.get(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/api/goods/</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> cate.id).then(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res){
                     self.goods</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">res.body;   
                     self.curcate</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">cate.categoryName;
                     </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">alert(JSON.stringify(self.goods));</span>

},function(){
alert(
"获取 goods 失败!");
});
},
getGoodsListByPage:
function(ps,pno){
var self = this;
//按分页检索商品列表
this.$http.get('/api/goods' +'?pagesize='+ps +'&page=' + pno).then(function(res){
self.goods
=res.body;
self.curcate
="ALL";
//alert(JSON.stringify(self.goods));
},function(){
alert(
"获取 goods 失败!");
});
},
addToShoppingCart:
function(goods){
//加入购物车
var self = this;
var qty=prompt('请输入购买数量',1);
this.$http.post('/api/addToShoppingCart',{goodsid:goods.id,goodsqty:qty}).then(function(res){
var rs=res.body;
alert(rs.msg);
self.cartCount
=rs.data.cartCount;
},
function(){
alert(
"加入购物车失败");
});
}
}
});

</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</body>
</html>

View Code

detail.html(商品详情)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>商品详情 - 梦在旅途的电商小店</title>
<meta name="author" content="www.zuowenjun.cn" >
<script src="https://cdn.jsdelivr.net/npm/vue" type="text/javascript"></script>
<script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>
<style type="text/css">
        .clfx {clear:both;display:block;}
        .row{width:100%;margin:10px 0;}
        .lbox{float:left;width:40%;min-height: 100px;}
        .rbox{float:right;width:50%;}
        .rbox ul li{margin:50px auto;}
        body{padding-top:51px;}
        #topbar{height:50px;line-height:50px;margin:0;width:100%;background-color:WhiteSmoke;
        position: fixed;top:0;border-bottom:1px solid darkgray;text-align: right;}
</style>

</head>
<body>
<div id="app">
<div id="topbar">
<a href="/cartlist.html" target="_blank">购物车 (已加入商品数量:{{cartCount}})</a>&nbsp;|&nbsp;
<a href="/admin.html" target="_blank">管理后台</a>&nbsp;&nbsp;&nbsp;&nbsp;
</div>
<div class="row">
<div class="lbox">
<img :src="goods.picture" style="width:100%;height:100%;margin:0;padding:0;">
</div>
<div class="rbox">
<ul>
<li><strong>{{goods.title}}</strong></li>
<li>价格:¥{{goods.price}}</li>
<li>购买数量:<input v-model="buyqty" value="1"></li>
<li>购买价格:<span>{{buyprice}}</span></li>
<li><button @click="addToShoppingCart">加入购物车</button></li>
</ul>
</div>
<div class="clfx"></div>
</div>
<div class="row">
<h2>商品详细描述:</h2>
<hr/>
<p>{{goods.introduction}}</p>
</div>
</div>
<script type="text/javascript">
var vm=new Vue({
el:
"#app",
data:{
cartCount:
0,
buyqty:
1,
goods:{}
},
created:
function(){
var gid= getQueryString("gid");
var self = this;

             </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$http.get(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/api/goods-</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> gid).then(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res){
                 self.goods</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">res.body;  
                 </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">alert(JSON.stringify(self.goods));</span>

},function(){
alert(
"获取 goods 失败!");
});

             </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$http.get(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/api/cartlist</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">).then(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res){
                 self.cartCount</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">res.body.length;  
                 </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">alert(JSON.stringify(self.goods));</span>

},function(){
alert(
"获取购物车信息失败!");
});

        },
        computed:{
            buyprice:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(){
                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">return</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.buyqty </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">*</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.goods.price).toFixed(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">2</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
            }
        },
        methods:{
            addToShoppingCart:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(){
                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">alert(this.buyqty);</span>
                <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">加入购物车</span>
                <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> self </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;
                 </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$http.post(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/api/addToShoppingCart</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">,{goodsid:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.goods.id,goodsqty:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.buyqty}).then(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res){
                     </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> rs</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">res.body;
                     alert(rs.msg);
                     self.cartCount</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">rs.data.cartCount;
                    },</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(){
                        alert(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">加入购物车失败</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
                    });
            }
        }
    });
    
    </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> getQueryString(name) { 
        </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> reg </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">new</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> RegExp(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(^|&amp;)</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> name </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=([^&amp;]*)(&amp;|$)</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">i</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">); 
        </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> r </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> window.location.search.substr(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">1</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">).match(reg); 
        </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (r </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">!=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">null</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">) </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">return</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> unescape(r[</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">2</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">]); 
        </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">return</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">null</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">; 
    }
    
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</body>
</html>

View Code

cartlist.html(购物车)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>购物车详情 - 梦在旅途的电商小店</title>
<meta name="author" content="www.zuowenjun.cn" >
<script src="https://cdn.jsdelivr.net/npm/vue" type="text/javascript"></script>
<script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>
<style type="text/css">
    .toolbar{margin:10px 5px;}
    .carttable{width:100%;margin:0px;padding:5px;border:1px solid gray;}
    .carttable tr >*{border-bottom:1px solid gray;padding:5px;text-align: center;}
    .buybtn{background-color:green;border:none;width:280px;padding:20px;color:white;font-size:20pt;}
    #copy{margin-top:20px;text-align: center;}
</style>
</head>
<body>
    <div id="app">
        <div class="toolbar">
            <button @click="deleteItem()" :disabled="carts.length==0">移出购物车</button>&nbsp;|&nbsp;
            <button @click="clearCart()" :disabled="carts.length==0">清空购物车</button>
        </div>
        <div>
            <table class="carttable">
                <tr>
                    <th>选择</th>
                    <th>商品 ID</th>
                    <th>商品名称</th>
                    <th>预购买数量</th>
                    <th>价格</th>
                    <th>添加时间</th>
                </tr>
                <tr v-for="c in carts">
                    <td><input type="checkbox" class="chkitem" @click="checkitem(c,$event.target)" :checked="chkedItemIds.indexOf(c.id)>-1"></td>
                    <td>{{c.goodsId}}</td>
                    <td>{{c.inGoods.title}}</td>
                    <td>{{c.qty}}</td>
                    <td>¥{{(c.inGoods.price * c.qty).toFixed(2)}}</td>
                    <td>{{c.addedTime}}</td>
                </tr>
                <tr v-if="carts.length==0" style="text-align: center;">
                    <td colspan="6">空空如也,赶紧选购商品吧!~</td>
                </tr>
            </table>
        </div>
        <p style="text-align: center;">
            <button class="buybtn" @click="createOrder()" :disabled="carts.length==0">立即下单</button>
        </p>
    </div>
    <p id="copy">
    Copyright &copy;2019 &nbsp;
    www.zuowenjun.cn and zuowj.cnblogs.com demo all rights.
    </p>
    <script type="text/javascript">
        var vm=new Vue({
            el:"#app",
            data:{carts:[],
                chkedItemIds:[]},
            created:function(){
                var self = this;
             </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$http.get(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/api/cartlist</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">).then(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res){
                 self.carts</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">res.body;  
                 </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">alert(JSON.stringify(self.carts));</span>

},function(){
alert(
"获取购物车信息失败!");
});

        },
        methods:{
            checkitem:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(cart,chk){
                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">alert(chk.checked);</span>
                <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(chk.checked){
                    </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.chkedItemIds.push(cart.id);
                }</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">else</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{
                    </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.chkedItemIds.remove(cart.id);
                }
            },
            deleteItem:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(){
                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> self </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;
                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">alert(JSON.stringify(self.chkedItemIds));</span>
                 <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$http.post(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/api/deletecartitems-many</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">,self.chkedItemIds).then(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res){ 
                     self.carts</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> self.carts.filter(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(e){ </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">return</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> self.chkedItemIds.indexOf(e.id)</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">&lt;=-</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">1</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;});
                     alert(res.body.msg);
                    },</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(){
                        alert(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">删除失败!</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
                    });
            },
            clearCart:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(){
                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> self </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;
                 </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$http.post(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/api/deletecartitems-all</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">).then(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res){ 
                     self.carts</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">[];
                     alert(res.body.msg);
                    },</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(){
                        alert(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">删除失败!</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
                    });
            },
            createOrder:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(){
                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> self </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;
                 </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$http.post(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/api/createorder</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">).then(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res){ 
                     alert(res.body.msg);
                     </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res.body.code</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">==</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">0</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">){</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">如查下单成功,则清空购物车</span>

self.carts=[];
}
},
function(){
alert(
"下单失败!");
});
}
}
});

    Array.prototype.remove </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(val) { 
            </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> index </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.indexOf(val); 
            </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (index </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">&gt;</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">-</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">1</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">) { 
            </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.splice(index, </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">1</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">); 
            } 
        };
            
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</body>
</html>

View Code

orderlist.html(订单中心)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>订单详情 - 梦在旅途的电商小店</title>
<script src="https://cdn.jsdelivr.net/npm/vue" type="text/javascript"></script>
<script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>
<style type="text/css">
    table{border:solid 1px blue;border-collapse: collapse;width:100%;margin:10px 1px;}
    table tr >*{border:solid 1px blue,padding:5px;border:dotted 1px gray;}
    .cfmbar{text-align: center;}
    .cfmbar button{border:none;background-color:blue;color:#ffffff;padding:10px 50px;}
    #copy{margin-top:20px;text-align: center;}
</style>
</head>
<body>
    <div id="app">
        <div>
            <h2>订单列表:</h2>
            <table>
                <tr>
                    <th>订单号</th>
                    <th>商品数量</th>
                    <th>订单价格</th>
                    <th>完成否 (收货确认)</th>
                    <th>创建时间</th>
                    <th>查看订单详情</th>
                </tr>
                <tr v-for="o in shoppingOrders">
                    <td>{{o.id}}</td>
                    <td>{{o.totalqty}}</td>
                    <td>{{o.totalprice.toFixed(2)}}</td>
                    <td>{{o.iscompleted?"已收货":"待收货"}}</td>
                    <td>{{o.createtime}}</td>
                    <td><button @click="showOrderDetail(o)">查看</button></td>
                </tr>
                <tr v-if="shoppingOrders.length==0" style="text-align: center;">
                    <td colspan="6">没有任何订单信息!</td>
                </tr>
            </table>
        </div>
        <div v-if="viewOrder!=null">
            <h3>订单号【{{viewOrder.id}}】详情:</h3>
            <table>
                <tr>
                    <th>商品 ID</th>
                    <th>商品名称</th>
                    <th>购买数量</th>
                    <th>费用</th>
                </tr>
                <tr v-for="od in viewOrderDetails.details">
                    <td>{{od.goodsid}}</td>
                    <td>{{goodsName(od)}}</td>
                    <td>{{od.qty}}</td>
                    <td>¥{{od.totalprice.toFixed(2)}}</td>
                </tr>
            </table>
            <p class="cfmbar" v-if="!viewOrder.iscompleted">
                <button @click="confirmOrderCompleted(viewOrder)" >确认完成(已收货)</button>
            </p>
        </div>
    </div>
    <p id="copy">
    Copyright &copy;2019 &nbsp;
    www.zuowenjun.cn and zuowj.cnblogs.com demo all rights.
    </p>
    <script type="text/javascript">
        var vm=new Vue({
            el:"#app",
            data:{shoppingOrders:[],
                viewOrder:null,
                viewOrderDetails:null
            },
            created:function(){
                var self = this;
             </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$http.get(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/api/orders</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">).then(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res){
                 self.shoppingOrders</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">res.body;  
                 </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">alert(JSON.stringify(self.shoppingOrders));</span>

},function(){
alert(
"获取 orders 失败!");
});
},
computed:{
goodsName(){
//利用 JS 闭包实现传参
return function(od){
var goods= this.viewOrderDetails.goodss.filter(function(g){return g.id==od.goodsid })[0];
//alert(od.goodsid);
return goods.title;
}
}
},
methods:{
showOrderDetail:
function(o){
var self = this;
this.$http.post('/api/orderdetail',{orderId:o.id}).then(function(res){
if(res.body.code==0){
self.viewOrderDetails
=res.body.data;
//alert(JSON.stringify(self.viewOrderDetails));
}else{
alert(res.body.msg);
self.viewOrderDetails
=null;
o
=null;
}
self.viewOrder
=o;
},
function(){
alert(
"获取 orderdetail 失败!");
});
},
confirmOrderCompleted:
function(o){
var self = this;
this.$http.post('/api/confirmOrderCompleted',{orderId:o.id}).then(function(res){
alert(res.body.msg);
if(res.body.code==0){
self.viewOrder.iscompleted
=true;
}
}),
function(){
alert(
"确认订单完成失败!");
};
}
}
});

    </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> getQueryString(name) { 
        </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> reg </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">new</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> RegExp(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(^|&amp;)</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> name </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=([^&amp;]*)(&amp;|$)</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">i</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">); 
        </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> r </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> window.location.search.substr(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">1</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">).match(reg); 
        </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (r </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">!=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">null</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">) </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">return</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> unescape(r[</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">2</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">]); 
        </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">return</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">null</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">; 
    }
    
    
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</body>
</html>

View Code

admin.html(管理后台,由于 DEMO,故只实现商品的增、删功能,其余管理功能未实现,仅作演示)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>管理后台 - 梦在旅途的电商小店</title>
<meta name="author" content="www.zuowenjun.cn" >
<script src="https://cdn.jsdelivr.net/npm/vue" type="text/javascript"></script>
<script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>
<style type="text/css">
    table{border:solid 1px blue;border-collapse: collapse;width:100%;margin:10px 1px;}
    table tr >*{border:solid 1px blue,padding:5px;border:dotted 1px gray;}
    .gpic{width:100px;height:100px;text-align:center;vertical-align:middle;}
</style>
</head>
<body>
    <div id="app">
        <fieldset>
            <legend>管理商品:</legend>
            <table>
                <colgroup>
                    <col style="width:auto">
                    <col style="width:auto">
                    <col style="width:100px">
                    <col style="width:300px">
                    <col style="width:auto">
                    <col style="width:auto">
                    <col style="width:auto">
                    <col style="width:auto">
                    <col style="width:auto">
                </colgroup>
                <tr>
                    <th>商品 ID</th>
                    <th>商品名称</th>
                    <th>商品图片</th>
                    <th>商品介绍</th>
                    <th>单价</th>
                    <th>类别 ID</th>
                    <th>最后编辑者</th>
                    <th>最后编辑时间</th>
                    <th>操作</th>
                </tr>
                <tr style="background-color:orange;">
                    <td>{{editgoods.id}}</td>
                    <td><input type="text" v-model="editgoods.title"></td>
                    <td><img v-bind:src="editgoods.picture" class="gpic">
                    <input class="upload" type="file" id="gpicfile" @change="selectimg($event.target)" accept="image/png,image/gif,image/jpeg"></td>
                    <td><textarea v-model="editgoods.introduction"></textarea></td>
                    <td><input type="text" v-model="editgoods.price"></td>
                    <td>
                        <select v-model="editgoods.categoryId">
                            <option v-for="c in categorys" v-bind:value="c.id">{{c.categoryName}}</option>
                        </select>
                    </td>
                    <td>{{editgoods.lastEditBy}}</td>
                    <td>{{editgoods.lastEditTime}}</td>
                    <td><button @click="savegoods(editgoods)">保存</button></td>
                </tr>
                <tr v-for="g in goodss">
                    <td>{{g.id}}</td>
                    <td>{{g.title}}</td>
                    <td><img v-bind:src="g.picture" class="gpic"></td>
                    <td>{{g.introduction}}</td>
                    <td>{{g.price}}</td>
                    <td>{{g.categoryId}}</td>
                    <td>{{g.lastEditBy}}</td>
                    <td>{{g.lastEditTime}}</td>
                    <td><button @click="editgoods(g)" disabled="disabled">修改</button>&nbsp;|&nbsp;<!-- UI 暂不实现修改,禁用 -->
                    <button @click="delgoods(g)">删除</button></td>
                </tr>
            </table>
        </fieldset>
    </div>
    <script type="text/javascript">
        var vm=new Vue({
            el:"#app",
            data:{categorys:[],
                goodss:[],
                editgoods:{
                    id:null,
                    title:null,
                    picture:null,
                    price:0.00,
                    introduction:null,
                    categoryId:1,
                    lastEditBy:"zuowenjun",
                    lastEditTime:null
                }
            },
            created:function(){
                this.$http.get('/api/categorys').then(function(res){
                     this.categorys=res.body;  
                    },function(){
                        alert("获取 categorys 失败!");});
            </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.getGoodsListByPage(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">100</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">,</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">1</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">DEMO,只加载第1页</span>
}, methods:{ getGoodsListByPage:function(ps,pno){ var self = this; //按分页检索商品列表 this.$http.get('/api/goods' +'?pagesize='+ps +'&page=' + pno).then(function(res){ self.goodss=res.body; //alert(JSON.stringify(self.goods)); },function(){ alert("获取 goods 失败!");}); }, selectimg:function(el){
                let gpic</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">el.files[</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">0</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">];
                let type</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">gpic.type;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">文件的类型,判断是否是图片</span>

let size=gpic.size;//文件的大小,判断图片的大小
if('image/gif, image/jpeg, image/png, image/jpg'.indexOf(type) == -1){
alert(
'请选择我们支持的图片格式!');
return false;
}
if(size>3145728){
alert(
'请选择 3M 以内的图片!');
return false;
}
var uri ='';

                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.editgoods.picture</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">URL.createObjectURL(gpic);
            },
            savegoods:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(g){
                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> fileDom</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">document.getElementById(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">gpicfile</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
                let formData </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">new</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> FormData();
                formData.append(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">id</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.editgoods.id);
                formData.append(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">title</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.editgoods.title);
                formData.append(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">picture</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, fileDom.files[</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">0</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">]);
                formData.append(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">price</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.editgoods.price);
                formData.append(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">introduction</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.editgoods.introduction);
                formData.append(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">categoryId</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.editgoods.categoryId);
                
                let config </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {
                          headers: {
                            </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">Content-Type</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">multipart/form-data</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
                          }
                        }
                
                  </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$http.post(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/api/savegoods</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, formData, config).then(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (res) {
                      alert(res.body.msg);
                      </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res.body.code</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">==</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">0</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">){
                          </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.goodss.unshift(res.body.data);</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">插入到数组最新面</span>
                          <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.editgoods</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">重新初始化,以便实现清空所有编辑框</span>

id:null,
title:
null,
picture:
null,
price:
0.00,
introduction:
null,
categoryId:
1,
lastEditBy:
"zuowenjun",
lastEditTime:
null
};
}
});
},
delgoods:
function(g){
this.$http.get('/api/delgoods/' + g.id).then(function(res){
alert(res.body.msg);
if(res.body.code==0){
this.goodss.remove(g);
}
},
function(){
alert(
"删除 goods 失败!");
});
}
}
});

    Array.prototype.remove </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(val) { 
        </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> index </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.indexOf(val); 
        </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (index </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">&gt;</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">-</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">1</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">) { 
        </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.splice(index, </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">1</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">); 
        } 
    };
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</body>
</html>

View Code

前端交互所需要 API(因为是 DEMO,故所有的 API ACTION 方法都在 Apicontroller 中),代码如下:

package cn.zuowenjun.boot.controller;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import cn.zuowenjun.boot.domain.;
import cn.zuowenjun.boot.service.
;

/*

  • ALL REST API
    */
    @RestController
    @RequestMapping(
    "/api")
    public class ApiController {

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private ShoppingOrderService shoppingOrderService;

    @Autowired
    private ShopUserService shopUserService;

    private String getCurrentShopper() {
    String shopper
    = shopUserService.getCurrentLoginUser();
    return shopper;
    }

    @PostMapping(value="/login",produces = "application/json;charset=utf-8")
    public ApiResultMsg login(@RequestBody Map<String,String> requestMap) {
    String userid
    =requestMap.get("userid");
    String upwd
    =requestMap.get("upwd");
    String loginResult
    = shopUserService.login(userid, upwd);
    if(loginResult==null) {
    return new ApiResultMsg(0,"OK",null);
    }
    else {
    return new ApiResultMsg(-1,"登录失败:" + loginResult,null);
    }

    }

    @GetMapping(value = "/categorys", produces = "application/json;charset=utf-8")
    public List<GoodsCategory> getAllGoodsCategorys() {
    return goodsService.getAllGoodsCategoryList();
    }

    @GetMapping(value = "/goods/{cateid}", produces = "application/json;charset=utf-8")
    public List<Goods> getGoodsList(@PathVariable(name = "cateid") int categoryid) {
    return goodsService.getGoodsListByCategory(categoryid);
    }

    @GetMapping(value = "/goods", produces = "application/json;charset=utf-8")
    public List<Goods> getGoodsList(@RequestParam(name = "pagesize", required = false) String spageSize,
    @RequestParam(name
    = "page", required = false)String spageNo) {

     </span><span style="color: rgba(0, 0, 255, 1)">int</span> pageSize =<span style="color: rgba(0, 0, 0, 1)"> tryparseToInt(spageSize);
     </span><span style="color: rgba(0, 0, 255, 1)">int</span> pageNo =<span style="color: rgba(0, 0, 0, 1)"> tryparseToInt(spageNo);
    
     pageSize </span>= pageSize &lt;= 0 ? 10<span style="color: rgba(0, 0, 0, 1)"> : pageSize;
     pageNo </span>= pageNo &lt;= 1 ? 1<span style="color: rgba(0, 0, 0, 1)"> : pageNo;
     </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> goodsService.getGoodsListByPage(pageSize, pageNo);
    

    }

    @GetMapping(value = "/goodsmany", produces = "application/json;charset=utf-8")
    public List<Goods> getGoodsListByMultIds(@RequestBody int[] ids) {
    return goodsService.getGoodsListByMultIds(ids);
    }

    @PostMapping(value = "/addToShoppingCart", produces = "application/json;charset=utf-8")
    public ApiResultMsg addToShoppingCart(@RequestBody Map<String, Integer> json) {
    int goodsId = json.get("goodsid");
    int qty = json.get("goodsqty");
    ApiResultMsg msg
    = new ApiResultMsg();
    if (goodsId <= 0) {
    msg.setCode(
    101);
    msg.setMsg(
    "该商品 ID 无效");
    return msg;
    }

     String shopper </span>=<span style="color: rgba(0, 0, 0, 1)"> getCurrentShopper();
     ShoppingCart shoppingCart </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> ShoppingCart(0, shopper, goodsId, qty, <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date());
    
     shoppingOrderService.insertShoppingCart(shoppingCart);
    
     msg.setCode(</span>0<span style="color: rgba(0, 0, 0, 1)">);
     msg.setMsg(</span>"添加购物车成功!"<span style="color: rgba(0, 0, 0, 1)">);
    
     </span><span style="color: rgba(0, 0, 255, 1)">int</span> cartCount =<span style="color: rgba(0, 0, 0, 1)"> shoppingOrderService.getShoppingCartBuyCount(shopper);
     HashMap</span>&lt;String, Object&gt; data = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">();
     data.put(</span>"cartCount"<span style="color: rgba(0, 0, 0, 1)">, cartCount);
    
     msg.setData(data);
    
     </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> msg;
    

    }

    @GetMapping(value = "/goods-{gid}", produces = "application/json;charset=utf-8")
    public Goods getGoods(@PathVariable("gid") int goodsId) {
    return goodsService.getGoods(goodsId);
    }

    @GetMapping(value = "/cartlist", produces = "application/json;charset=utf-8")
    public List<ShoppingCart> getShoppingCartList() {
    String shopper
    = getCurrentShopper();
    return shoppingOrderService.getShoppingCartList(shopper);
    }

    @PostMapping(value = "/deletecartitems-{mode}", produces = "application/json;charset=utf-8")
    public ApiResultMsg deleteShoppingCartItems(@PathVariable("mode") String mode,
    @RequestBody(required
    = false) int[] cartIds) {
    if (mode.equalsIgnoreCase("all")) {
    String shopper
    = getCurrentShopper();
    shoppingOrderService.clearShoppingCart(shopper);
    }
    else {
    for (int id : cartIds) {
    shoppingOrderService.deleteShoppingCart(id);
    }
    }

     </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> ApiResultMsg(0, "删除成功!", <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
    

    }

    @PostMapping(value = "/createorder", produces = "application/json;charset=utf-8")
    public ApiResultMsg createShoppingOrder() {

     String shopper </span>=<span style="color: rgba(0, 0, 0, 1)"> getCurrentShopper();
     ApiResultMsg msg </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ApiResultMsg();
     </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (shoppingOrderService.createShoppingOrderByShopper(shopper)) {
         msg.setCode(</span>0<span style="color: rgba(0, 0, 0, 1)">);
         msg.setMsg(</span>"恭喜你,下单成功!"<span style="color: rgba(0, 0, 0, 1)">);
     } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
         msg.setCode(</span>101<span style="color: rgba(0, 0, 0, 1)">);
         msg.setMsg(</span>"对不起,下单失败,请重试!"<span style="color: rgba(0, 0, 0, 1)">);
     }
    
     </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> msg;
    

    }

    @RequestMapping(path = "/orders", produces = "application/json;charset=utf-8", method = RequestMethod.GET) // 等同于 @GetMapping
    public List<ShoppingOrder> getShoppingOrderList() {
    String shopper
    = getCurrentShopper();
    return shoppingOrderService.getShoppingOrderList(shopper);
    }

    @RequestMapping(path = "/orderdetail", produces = "application/json;charset=utf-8", method = RequestMethod.POST) // 等同于 @PostMapping
    public ApiResultMsg getShoppingOrderDetail(@RequestBody Map<String, String> requestJosn) {
    String orderId
    = requestJosn.get("orderId");
    List
    <ShoppingOrderDetail> orderDetails = shoppingOrderService.getShoppingOrderDetail(tryparseToInt(orderId));
    ApiResultMsg msg
    = new ApiResultMsg();
    if (orderDetails.size() > 0) {

         </span><span style="color: rgba(0, 0, 255, 1)">int</span>[] goodsIds = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">[orderDetails.size()];
         </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; orderDetails.size(); i++<span style="color: rgba(0, 0, 0, 1)">) {
             goodsIds[i] </span>=<span style="color: rgba(0, 0, 0, 1)"> orderDetails.get(i).getGoodsid();
         }
    
         List</span>&lt;Goods&gt; goodsList =<span style="color: rgba(0, 0, 0, 1)"> goodsService.getGoodsListByMultIds(goodsIds);
         HashMap</span>&lt;String, Object&gt; data = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">();
         data.put(</span>"details"<span style="color: rgba(0, 0, 0, 1)">, orderDetails);
         data.put(</span>"goodss"<span style="color: rgba(0, 0, 0, 1)">, goodsList);
    
         msg.setCode(</span>0<span style="color: rgba(0, 0, 0, 1)">);
         msg.setData(data);
    
     } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
         msg.setCode(</span>101<span style="color: rgba(0, 0, 0, 1)">);
         msg.setMsg(</span>"获取订单详情信息失败!"<span style="color: rgba(0, 0, 0, 1)">);
     }
    
     </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> msg;
    

    }

    //这里示例配置多个 URL 请求路径
    @PostMapping(path= {"/confirmOrderCompleted","/cfmordercompl"},produces="application/json;charset=utf-8")
    public ApiResultMsg confirmOrderCompleted(@RequestBody Map<String, String> requestJosn) {
    String reqOrderId
    = requestJosn.get("orderId");
    ApiResultMsg msg
    =new ApiResultMsg();
    try {

         </span><span style="color: rgba(0, 0, 255, 1)">int</span> orderId=<span style="color: rgba(0, 0, 0, 1)">tryparseToInt(reqOrderId);
         ShoppingOrder  order</span>=<span style="color: rgba(0, 0, 0, 1)"> shoppingOrderService.getShoppingOrder(orderId);
         order.setIscompleted(</span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
         shoppingOrderService.updateShoppingOrder(order);
         msg.setCode(</span>0<span style="color: rgba(0, 0, 0, 1)">);
         msg.setMsg(</span>"确认订单完成成功(已收货)"<span style="color: rgba(0, 0, 0, 1)">);
     }</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
         msg.setCode(</span>101<span style="color: rgba(0, 0, 0, 1)">);
         msg.setMsg(</span>"确认订单完成失败:" +<span style="color: rgba(0, 0, 0, 1)"> e.getMessage());
     }
    
     </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> msg;
    

    }

    @PostMapping(path="/savegoods",produces="application/json;charset=utf-8",consumes="multipart/form-data")
    public ApiResultMsg saveGoods(@RequestParam("picture")MultipartFile gpic,HttpServletRequest request) {
    ApiResultMsg msg
    =new ApiResultMsg();
    try
    {
    Goods goods
    =new Goods();
    goods.setId(tryparseToInt(request.getParameter(
    "id")));
    goods.setTitle(request.getParameter(
    "title"));
    goods.setPrice(
    new BigDecimal(request.getParameter("price")));
    goods.setIntroduction(request.getParameter(
    "introduction"));
    goods.setCategoryId(tryparseToInt(request.getParameter(
    "categoryId")));
    goods.setLastEditBy(getCurrentShopper());
    goods.setLastEditTime(
    new Date());

         </span><span style="color: rgba(0, 0, 255, 1)">if</span>(goods.getId()&lt;=0<span style="color: rgba(0, 0, 0, 1)">) {
             goodsService.insertGoods(goods, gpic);
         } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
             goodsService.updateGoods(goods, gpic);
         }
    
         msg.setCode(</span>0<span style="color: rgba(0, 0, 0, 1)">);
         msg.setMsg(</span>"保存成功!"<span style="color: rgba(0, 0, 0, 1)">);
         msg.setData(goods);
    
     }</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
         msg.setCode(</span>101<span style="color: rgba(0, 0, 0, 1)">);
         msg.setMsg(</span>"保存失败:" +<span style="color: rgba(0, 0, 0, 1)"> e.getMessage());
     }
    
     </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> msg;
    

    }

    @GetMapping(path="/delgoods/{gid}",produces="application/json;charset=utf-8")
    public ApiResultMsg deleteGoods(@PathVariable("gid") int goodsId) {
    goodsService.deleteGoods(goodsId);
    ApiResultMsg msg
    =new ApiResultMsg();
    msg.setCode(
    0);
    msg.setMsg(
    "删除商品成功!");

     </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> msg;
    

    }

    private int tryparseToInt(String str) {
    try {
    return Integer.parseInt(str);
    }
    catch (Exception e) {
    return -1;
    }
    }

}

View Code

REST API controller 与普通的 MVC controller 用法上基本相同,只是 REST API ACTION 返回的是数据内容本身 (@RestController 或 @Controller+@ResponseBody),而 MVC ACTION 一般返回 view

 4.4 添加身份认证拦截器、日志记录等

  因为演示的是电商购物场景,既有下单又有后台管理,故这里我增加了登录视图及登录拦截器,以完成对部份页面及 API 的权限控制,实现代码如下:

  4.4.1. 设计 login.html(登录)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录入口  - 梦在旅途的电商小店</title>
<meta name="author" content="www.zuowenjun.cn" >
<script src="https://cdn.jsdelivr.net/npm/vue" type="text/javascript"></script>
<script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>
</head>
<body>
    <div id="app">
        <form method="post" @submit.prevent="loginsubmit">
        <p>用户 ID:</p>
        <p><input type="text" v-model="uid"></p>
                <p>密码:</p>
        <p><input type="password" v-model="pwd"></p>
        <p>
            <button type="submit">登录</button>
        </p>
        </form>
    </div>
    <script type="text/javascript">
        var vm=new Vue({
            el:"#app",
            data:{
                uid:null,
                pwd:null
            },
            methods:{
                loginsubmit:function(){
                 </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$http.post(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/api/login</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">,{userid:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.uid,upwd:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.pwd}).then(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(res){
                     </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> rs</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">res.body;
                     </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(rs.code</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">==</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">0</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">){
                         window.location.href</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">index.html</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;
                     }</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">else</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{
                         alert(rs.msg);
                     }
                    },</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(){
                        alert(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">登录请求失败!</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
                    });
            }
        }
    });
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</body>
</html>

View Code

  4.4.2. 自定义实现 HandlerInterceptor 的登录验证拦截器:LoginInterceptor,代码如下:(注意我是将该拦截器放在根包中 cn.zuowenjun.boot)

package cn.zuowenjun.boot;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import com.fasterxml.jackson.databind.ObjectMapper;

import cn.zuowenjun.boot.domain.ApiResultMsg;

@Component
public class LoginInterceptor implements HandlerInterceptor {

</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> Logger logger = LoggerFactory.getLogger(LoginInterceptor.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        </span><span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> Exception {

    HttpSession session </span>=<span style="color: rgba(0, 0, 0, 1)"> request.getSession();
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (session.getAttribute("loginUser") == <span style="color: rgba(0, 0, 255, 1)">null</span>) {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 未登录则转到登录页面</span>
        <span style="color: rgba(0, 0, 255, 1)">boolean</span> isAjaxRequest = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
        </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> isAcceptJSON = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (request.getHeader("x-requested-with") != <span style="color: rgba(0, 0, 255, 1)">null</span>
                &amp;&amp; request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest"<span style="color: rgba(0, 0, 0, 1)">)) {
            isAjaxRequest </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
        }

        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (request.getHeader("Accept") != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; request.getHeader("Accept").contains("application/json"<span style="color: rgba(0, 0, 0, 1)">)) {
            isAcceptJSON </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
        }

        </span><span style="color: rgba(0, 0, 255, 1)">if</span>(isAjaxRequest ||<span style="color: rgba(0, 0, 0, 1)"> isAcceptJSON) {
            
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用jackson序列化JSON</span>
            ApiResultMsg msg=<span style="color: rgba(0, 0, 255, 1)">new</span> ApiResultMsg(-1,"未登录,禁止访问",<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
            ObjectMapper mapper </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ObjectMapper();
            String msgJson</span>=<span style="color: rgba(0, 0, 0, 1)"> mapper.writeValueAsString(msg);
            
            responseJson(response,msgJson);
            
        }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
            
            response.sendRedirect(</span>"/login.html"<span style="color: rgba(0, 0, 0, 1)">);
        }
        </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
}

</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> responseJson(HttpServletResponse response, String json) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> Exception {
    PrintWriter writer </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    response.setCharacterEncoding(</span>"UTF-8"<span style="color: rgba(0, 0, 0, 1)">);
    response.setContentType(</span>"applcation/json; charset=utf-8"<span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        writer </span>=<span style="color: rgba(0, 0, 0, 1)"> response.getWriter();
        writer.print(json);

    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
        logger.error(</span>"response error"<span style="color: rgba(0, 0, 0, 1)">, e);
    } </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (writer != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
            writer.close();
    }
}

}

View Code

  代码比较简单,主要是判断 session 中是否有记录登录的用户名,如果没有则表示未登录,然后根据是 AJAX 请求或需要返回 JSON 的情况则返回 JSON,否则直接跳转到 login.html 页面。

  4.4.3. 自定义实现 WebMvcConfigurer 的配置类:SpringbootdemoAppConfigurer,重写 addInterceptors 方法,在该方法中把 LoginInterceptor 实例加入到拦截器管道中,以便交由 spring MVC 进行管理,代码如下:(同样放在根包中)

package cn.zuowenjun.boot;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;

@Configuration
public class SpringbootdemoAppConfigurer implements WebMvcConfigurer {

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> LoginInterceptor loginInterceptor;

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> addInterceptors(InterceptorRegistry registry) {
    InterceptorRegistration registration </span>=<span style="color: rgba(0, 0, 0, 1)"> registry.addInterceptor(loginInterceptor);
    registration.addPathPatterns(</span>"/**"<span style="color: rgba(0, 0, 0, 1)">);
    registration.excludePathPatterns(</span>"/*.html","/uploadimgs/*","/error","/api/login","/api/categorys","/api/goods*","/api/goods/*"<span style="color: rgba(0, 0, 0, 1)">,
            </span>"/hello/*","/test/*"<span style="color: rgba(0, 0, 0, 1)">);
}

}

View Code

注意我这里是拦截所有路径,然后使用 excludePathPatterns 来排除不需要拦截的路径,如果需要拦截的路径比较少,可以直接指定拦截的具体路径,这样就不用排除了。

  4.4.4. 另外补充一个功能点说明:一般一个应用程度都会有日志记录,这里也不能少,spring boot 中默认实现了:slf4j+logback(slf4j 是一个日志门面接口,logback 是 slf4j 接口的实现,这样搭配比较好,可以随时更换日志实现框架),先在 application.properties 配置日志的基本参数,如下所示:( 详细集成配置,可参见:https://www.jianshu.com/p/88b03b03570c)

#logging.config=xxxx  #可以指定单独的日志配置 XML 文件,进行更丰富的设置,这里未采用
logging.level.root=info
logging.level.cn.zuowenjun.boot.mapper=debug
logging.file=springbootdemo.log

配置好后,然后在相应的类中直接使用即可,用法如下:(具体可见上面的 GoodsServiceImpl 代码)

private static Logger logger=LoggerFactory.getLogger(GoodsServiceImpl.class);//通过日志工厂获得一个日志记录实例

logger.info("日志信息");//有多个日志级别可用,但注意需要配置中的 root 级别相对应,比如目前是配置了 info,如果使用 debug,可能就不会输出日志到文件

  4.5 效果展示:(全部采用 HTML+AJAX 静态交互)

   通过以上的后端 API 代码 + 基于 VUE 的前端 HTML,就完成了一个简单的电商物购 DEMO,效果截图如下:

  主页:(加入购物车后,右上角的”购物车 (已加入商品数量:0)“ 数字变自动同步更新)

商品详情:

购物车:

订单管理:

后台管理(商品管理):

添加商品后,自动加入到列表第一行,如果删除则移除删除的商品所在行

 

本文示例项目源码,请参见 GIT:https://github.com/zuowj/springbootdemo