前言
上一章我们已经基本把小马哥商城的基本表设计好,这一章节,我们开始编写我们的项目代码。首先一个商城应该要有商品,那么我们先把商品上传到数据库里面。
商品上架
在spring boot的官网上快速的初始化项目,下载压缩包后解压,通过idea导入项目。点击file->new->module from existing sources,选择我们刚刚解压的项目。
这次的项目,我们的将application.properties重命名为application.yml。对应的yml格式的写法跟properties有一些不一样,不过yml的写法结构,会让我们更加清楚的了解spring的配置。yml是结构树的形式
spring:
datasource:
#配置驱动
driver-class-name: com.mysql.jdbc.Driver
#配置数据库地址
url: jdbc:mysql://localhost:3306/xiaoma_mall?serverTimezone=UTC
#配置mysql账号
username: root
#配置mysql密码
password: 123456
#xml文件的位置
mybatis:
mapperLocations: classpath:/mapper/**/*.xml
#输出日志
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
为了让我们的idea更加强大,我们需要安装一个mybatis插件。点file->setting,选择Plugins,在marketplace搜索mybatis,现在安装free mybatis plugin。安装完后重启idea才能生效的。
idea重启后,我们就开始新建包和类。
相应的代码
//商品
public class Good {
//自增id
private int id;
//商品名称
private String name;
//商品描述
private String remark;
//商品价格
private BigDecimal price;
//商品图片
private String image;
//商品类型
private int nameType;
//创建时间
private Date createTime;
//状态
private int status;
//创建者
private int createUser;
...省略 set get 方法
}
@Component
@Mapper
public interface GoodDao {
void add(Good good);
}
刚才我们安装了mybatis插件,在add方法会出现红色的波浪线,将鼠标放在add上后,用键盘alt+enter,选择 generate statement,将会在goodMapper生成<insert id="add"></insert>,我们在insert里面编写sql就可以了。
之前我们在写动态sql的时候,字段判断我们都是 field != null and field != '' 这样的写法,所以我们不希望存到数据库中的字段为null或空字符串,所以我们要进行判断,在重复写上面的表达式的时候,其实我们可以封装一个工具类来替代这种写。
在com.xiaoma.mall下新建一个utils包,创建一个DaoParamsUtil类
/**
* 字段检测工具类
*
*/
public class DaoParamsUtil {
/**
* 判断字段是否为空字符串
*
* @param o 将传进来的字段提升为Object类型
* @return true 为null或空字符串
* false 否
*/
public static boolean isBlank(Object o) {
if (o == null) {
return true;
} else {
if (o instanceof String) {
if ("".equals(o.toString().trim())) {
return true;
}
}
return false;
}
}
}
工具类编写完后,我们可以通过@包名.类名@方法名
<insert id="add">
insert into good (
<trim suffixOverrides=",">
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(name)">
name,
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(remark)">
remark,
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(price)">
price,
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(image)">
image,
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(nameType)">
name_type,
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(createTime)">
create_time,
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(status)">
status,
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(createUser)">
create_user
</if>
</trim>
)
values(
<trim suffixOverrides=",">
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(name)">
#{name},
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(remark)">
#{remark},
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(price)">
#{price},
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(image)">
#{image},
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(nameType)">
#{nameType},
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(createTime)">
#{createTime},
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(status)">
#{status},
</if>
<if test="!@com.xiaoma.mall.utils.DaoParamsUtil@isBlank(createUser)">
#{createUser}
</if>
</trim>
)
</insert>
<!--
<trim suffixOverrides=","> 表示当拼接的时候结尾符号为逗号时将自动帮我去除,感叹号取反的意思。
-->
动态sql拼接完后,我们先开始写我们的测试类。
//service 写简单的逻辑
public interface GoodService {
void add(Good good);
}
@Service
public class GoodServiceImpl implements GoodService {
@Autowired
private GoodDao goodDao;
@Override
@Transactional
public void add(Good good) {
goodDao.add(good);
}
}
MallApplicationTests 类编写我们的测试方法
@Autowired
GoodService goodService;
@Test
public void addGood(){
Good good = new Good();
good.setName("7号电池");
good.setPrice(new BigDecimal(2.5));
goodService.add(good);
}
商品图片我们还没有上传,现在我们用spring mvc 的文件上传功能MultipartFile
@RestController
@RequestMapping("good")
public class GoodController {
/**
* 商品文件上传接口
*
* @param file
* @return
*/
@PostMapping("shelves")
public String shelves(MultipartFile file) {
if (file == null) {
return "error";
}
//获取上传文件的后缀
int suffixIndex = file.getOriginalFilename().lastIndexOf(".");
String suffix = file.getOriginalFilename().substring(suffixIndex);
try {
//将上传的文件做md5加密,获取唯一的md5值
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(file.getBytes());
String md5Name = new BigInteger(md.digest()).toString(16);
//path文件路径, md5值昨晚文件名称
Path path = Paths.get("D:/demo/" + md5Name + suffix);
//保存文件
Files.write(path, file.getBytes());
} catch (IOException e) {
e.printStackTrace();
return "error";
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "ok";
}
}
用postman上传图片测试,返回ok代表上传成功。在我们配置的文件路径就能看到上传的图片了。
通过接口获取图片。
/**
* 获取图片
*
* @param imgName 图片名称
* @param response 响应对象
*/
@GetMapping("getGoodImg/{imgName}")
public void getGoodImg(@PathVariable("imgName") String imgName, HttpServletResponse response) {
Path path = Paths.get("D:/demo/" + imgName );
try {
//获取图片
byte[] img = Files.readAllBytes(path);
//组装响应头
response.setContentType("image/png".concat(";charset=UTF-8"));
response.setHeader("Content-Disposition", "inline; filename=" + imgName.split("\\.")[0] + "");
// 将图片字节写到响应输出流
ServletOutputStream servletOutputStream = response.getOutputStream();
servletOutputStream.write(img);
//将流输出并且关闭流
servletOutputStream.flush();
servletOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
现在我们尝试下通过html页面上架商品,首先在static目录下新建一个html文件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>小马哥商城</title>
</head>
<body>
<h3>商品上架</h3>
<form action="good/shelves" method="post" enctype="multipart/form-data">
<div>商品名称<input name="name"></div>
<div>商品描述<input name="remark"></div>
<div>商品价格<input name="price"></div>
<div>商品图片<input name="file" type="file"></div>
<div><button type="submit">上架</button></div>
</form>
</body>
</html>
good/shelves接口稍微改动下,
@Autowired
private GoodService goodService;
/**
* 商品文件上传接口
*
* @param file
* @return
*/
@PostMapping("shelves")
public String shelves(MultipartFile file, Good good) {
if (file == null) {
return "error";
}
//获取上传文件的后缀
int suffixIndex = file.getOriginalFilename().lastIndexOf(".");
String suffix = file.getOriginalFilename().substring(suffixIndex);
try {
//将上传的文件做md5加密,获取唯一的md5值
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(file.getBytes());
String md5Name = new BigInteger(md.digest()).toString(16);
//path文件路径, md5值昨晚文件名称
Path path = Paths.get("D:/demo/" + md5Name + suffix);
//保存文件
Files.write(path, file.getBytes());
good.setImage( md5Name + suffix);
goodService.add(good);
} catch (IOException e) {
e.printStackTrace();
return "error";
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "ok";
}
重新启动项目,在浏览器输入localhost:8080即可看到我们编写的Html页面。
输入好数据,点击上传就完成商品上架功能了。
小结
- 数据插入,动态sql工具类使用
- 图片上传,查看
- MultipartFile
- HttpServletResponse
- 输出流OutputStream 上面的知识我们需要上网搜索了解,在这里就不一一解析了。输出流在java基础部分没有讲解,在这里就简单介绍什么是流?流其实文件的一种表现形式,在我们的电脑中,看到的文件、图片等,都是window帮我们做好流的转换,这样我们才能看到图片。在java中读取文件,就是获取输入流 IntputStream,上传文件也是获取输入流,将 输入流 写到输出流OutputStream,最后将流关闭,就完成文件的写入了。流用完一定要关闭,不然就会一直占用该文件流,他们人无法使用。