JAVA WEB快速入门之从编写一个基于SpringBoot+Mybatis快速创建的REST API项目了解SpringBoot、SpringMVC REST API、Mybatis等相关知识
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.html,https://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; }
}
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><Goods> 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><Goods> getList(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> categoryId); @Select(</span>"<script>select * from TA_TestGoods where id in " +"<foreach item='item' index='index' collection='ids' open='(' separator=',' close=')'>#{item}</foreach>" +"order by id</script>"<span style="color: rgba(0, 0, 0, 1)">) List</span><Goods> 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; }
}
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><ShoppingCart><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)"><!--</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)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">></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)"></</span><span style="color: rgba(128, 0, 0, 1)">select</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">></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)"></</span><span style="color: rgba(128, 0, 0, 1)">select</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">></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)"></</span><span style="color: rgba(128, 0, 0, 1)">select</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">></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)"></</span><span style="color: rgba(128, 0, 0, 1)">insert</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">></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)"></</span><span style="color: rgba(128, 0, 0, 1)">update</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">></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)"></</span><span style="color: rgba(128, 0, 0, 1)">delete</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">></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)"></</span><span style="color: rgba(128, 0, 0, 1)">delete</span><span style="color: rgba(0, 0, 255, 1)">></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)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 添加mybatis生成器,以便通过maven build自动生成model、mapper及XML </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">></span>org.mybatis.generator<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">></span>mybatis-generator-core<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">></span>1.3.7<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">></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; }
}
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)"><</span><span style="color: rgba(128, 0, 0, 1)">commentGenerator</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">commentGenerator</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">jdbcConnection</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 生成model实体类文件位置 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">javaModelGenerator</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 生成mapper.xml配置文件位置 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> targetPackage这里指定包名,则会在如下的路径中生成多层级目录 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">sqlMapGenerator</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 生成mapper接口文件位置 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">javaClientGenerator</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">/></span><span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 指示ID为自增ID列,并在插入后返回该ID </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">table</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">context</span><span style="color: rgba(0, 0, 255, 1)">></span>
</generatorConfiguration>
由于涉及的知识点比较多,在此就不作介绍,请参见我给出的链接加以了解。
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<String><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)">; }
}
代码比较简单,主要是重写了 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;/*
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<FullyQualifiedJavaType> importedTypes = <span style="color: rgba(0, 0, 255, 1)">new</span> TreeSet<FullyQualifiedJavaType><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; }
}
另外顺便解决一个踩坑点:上面提到了,我们在 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)"><</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)">></span> <span style="color: rgba(0, 0, 255, 1)"><</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)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">table</span><span style="color: rgba(0, 0, 255, 1)">></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><ShoppingOrder><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><ShoppingOrderDetail> 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> && orderDetails.size()>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>>0<span style="color: rgba(0, 0, 0, 1)">); }
}
与 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><ShopUser> 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 ©<span th:text="${#dates.format(#dates.createToday(),'yyyy')}"></span>
www.zuowenjun.cn and zuowj.cnblogs.com demo all rights.
</p>
</body>
</html>
最后浏览:http://localhost:8080/test/userlist,效果如下图示:
四、利用 VUE+SpringMVC Rest API 编写实现前后端分离的电商购物 Demo(浏览商品、添加购物车、下单、完成)
说明:由于数据访问层(或称:数据持久层)已由Mybatis Generator完成了,现在就只要编写业务领域服务层(接口层、实现层),API 接入层即可完成后端开发,然后再开发设计前端页面即可(前端与后端交互使用 AJAX)
4.1. 在 cn.zuowenjun.boot.service 包中定义相关的业务领域服务接口
//ShopUserService.javapackage cn.zuowenjun.boot.service;
import java.util.List;
import cn.zuowenjun.boot.domain.ShopUser;
public interface ShopUserService {
List</span><ShopUser><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><Goods> 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><Goods> getGoodsListByCategory(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> categoryId); List</span><Goods> 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><GoodsCategory><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><ShoppingOrder><span style="color: rgba(0, 0, 0, 1)"> getShoppingOrderList(String shopper); List</span><ShoppingOrderDetail> 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<ShoppingOrderDetail><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><ShoppingCart><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);
}
如上代码示,我仅定义了三个 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<ShopUser><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) &&<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<Goods> 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<Goods> 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<Goods> 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> && !<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> && !<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> && !<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<GoodsCategory><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<ShoppingOrder><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<ShoppingOrderDetail> 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><ShoppingCart> 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()<=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><ShoppingOrderDetail> orderDetails=<span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList<><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<ShoppingOrderDetail><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<ShoppingCart><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); }
}
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> | <a href="/orderlist.html" target="_blank">订单中心</a> | <a href="/admin.html" target="_blank">管理后台</a> </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 ©2019 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)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
</body>
</html>
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> |
<a href="/admin.html" target="_blank">管理后台</a>
</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)">(^|&)</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)">=([^&]*)(&|$)</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)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
</body>
</html>
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> | <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 ©2019 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)"><=-</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)">></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)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
</body>
</html>
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 ©2019 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)">(^|&)</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)">=([^&]*)(&|$)</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)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
</body>
</html>
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> | <!-- 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 失败!");});}, 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){</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>
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)">></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)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
</body>
</html>
前端交互所需要 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 <= 0 ? 10<span style="color: rgba(0, 0, 0, 1)"> : pageSize; pageNo </span>= pageNo <= 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><String, Object> data = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap<><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 < 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><Goods> goodsList =<span style="color: rgba(0, 0, 0, 1)"> goodsService.getGoodsListByMultIds(goodsIds); HashMap</span><String, Object> data = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap<><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()<=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;
}
}}
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)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
</body>
</html>
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> && 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> && 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(); } }
}
代码比较简单,主要是判断 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)">); }
}
注意我这里是拦截所有路径,然后使用 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