学习目标
- 连接数据库
- Mybatis数据表映射关系的配置
- dao -> service -> controller层代码的编写,Junit的使用
- Session,图片处理工具Thumbnailator的使用
- suimobile前端设计与开发
Dao层
创建店铺
- 创建ShopDao 接口
package com.imooc.o2o.dao;
import com.imooc.o2o.entity.Shop;
public interface ShopDao {
// 新增店铺 返回1成功 返回-1失败
int insertShop(Shop shop);
}
- 创建ShopDao.xml映射文件
INSERT INTO
tb_shop(owner_id, area_id, shop_category_id,shop_name,
shop_desc, shop_addr, phone, shop_img, priority, create_time,
last_edit_time, enable_status, advice)
VALUES
(#{owner.userId}, #{area.areaId}, #{shopCategory.shopCategoryId},
#{shopName}, #{shopDesc}, #{shopAddr}, #{phone},
#{shopImg}, #{priority}, #{createTime},
#{lastEditTime}, #{enableStatus}, #{advice})
-
测试,新建ShopDaoTest
测试前,由于要用到两个外键,所有先在数据表中先添加两条数据
package com.imooc.o2o.dao;
import com.imooc.o2o.BaseTest;
import com.imooc.o2o.entity.Area;
import com.imooc.o2o.entity.PersonInfo;
import com.imooc.o2o.entity.Shop;
import com.imooc.o2o.entity.ShopCategory;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date;
import static org.junit.Assert.assertEquals;
public class ShopDaoTest extends BaseTest {
@Autowired
private ShopDao shopDao;
@Test
public void testInsertShop() {
Shop shop = new Shop();
PersonInfo owner = new PersonInfo();
Area area = new Area();
ShopCategory shopCategory = new ShopCategory();
owner.setUserId(1L);
area.setAreaId(2);
shopCategory.setShopCategoryId(1L);
shop.setOwner(owner);
shop.setArea(area);
shop.setShopCategory(shopCategory);
shop.setShopName("测试的店铺");
shop.setShopDesc("test");
shop.setPhone("test");
shop.setShopImg("test");
shop.setCreateTime(new Date());
shop.setEnableStatus(1);
shop.setAdvice("审核中");
int effectedNum = shopDao.insertShop(shop);
assertEquals(1, effectedNum);
}
}
-
测试结果
更新店铺
- 在ShopDao接口中,新增一个更新商铺的方法
// 更新店铺信息
int updateShop(Shop shop);
- 在mapper/ShopDao.xml文件里添加相应的映射
UPDATE tb_shop
shop_name=#{shopName},
shop_desc=#{shopDesc},
shop_addr=#{shopAddr},
phone=#{phone},
shop_img=#{shopImg},
priority=#{priority},
last_edit_time=#{lastEditTime},
enable_status=#{enableStatus},
advice=#{advice},
area_id=#{area.areaId},
shop_category_id=#{shopCategory.shopCategoryId}
WHERE shop_id = #{shopId}
- 添加一个update的测试方法
@Test
public void testUpdateShop() {
Shop shop = new Shop();
shop.setShopId(1L);
PersonInfo owner = new PersonInfo();
Area area = new Area();
ShopCategory shopCategory = new ShopCategory();
owner.setUserId(5L);
area.setAreaId(2);
shopCategory.setShopCategoryId(1L);
shop.setOwner(owner);
shop.setArea(area);
shop.setShopCategory(shopCategory);
shop.setShopName("测试的店铺");
// shop.setShopDesc("test");
// shop.setPhone("test");
// shop.setShopImg("test");
shop.setShopDesc("测试");
shop.setPhone("测试");
shop.setShopImg("测试");
shop.setCreateTime(new Date());
shop.setEnableStatus(1);
shop.setAdvice("审核中");
int effectedNum = shopDao.updateShop(shop);
assertEquals(1, effectedNum);
}
-
测试结果
Thumbnailator图片处理和封装Util
可以看看这个博客
https://blog.csdn.net/zmx729618/article/details/78729049
- 在http://mvnrepository.com/中下载
-
点击相应的版本
- 添加到项目的pox.xml文件中
net.coobird
thumbnailator
0.4.8
这样就成功引入底层的架包
- 新建一个com.imooc.o2o.util包
- 在utli包中新建imageUtil类
package com.imooc.o2o.util;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import static com.imooc.o2o.util.PathUtil.getImgBasePath;
public class ImageUtil {
private static String basePath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
private static final SimpleDateFormat sDateFormate = new SimpleDateFormat("yyyyMMddHHmmss");
private static final Random random = new Random();
/**
* 创建缩略图
*/
public static String generateThumbnail(CommonsMultipartFile thumbnail, String targetAddr) {
// 获取图片的随机图片名
String realFileName = getRandomFileName();
// 获取图片的拓展名
String extension = getFileExtension(thumbnail);
makeDirPath(targetAddr);
String relativeAddr = targetAddr + realFileName + extension;
File dest = new File(getImgBasePath() + relativeAddr);
try {
Thumbnails.of(thumbnail.getInputStream()).size(200, 200).outputQuality(0.25f).toFile(dest);
} catch (IOException e) {
throw new RuntimeException("创建缩略图失败:" + e.toString());
}
return relativeAddr;
}
/**
* 创建路径 /home/work/cuzz/xx.jpg
* 那么 home work xiangze 这三个文件都自动创建
* @param targetAddr
*/
private static void makeDirPath(String targetAddr) {
String realFileParentPath = PathUtil.getImgBasePath() + targetAddr;
File dirPath = new File(realFileParentPath);
// 如果路径不存在就递归的创建
if (!dirPath.exists()) {
dirPath.mkdirs();
}
}
/**
* 获取输入文件流的拓展名
* @param thumbnail
* @return
*/
private static String getFileExtension(CommonsMultipartFile cFile) {
// 获取原来的文件名
String originalFileName = cFile.getOriginalFilename();
return originalFileName.substring(originalFileName.lastIndexOf("."));
}
/**
* 生成随机文件名,当前年月日时分秒 + 5位随机数
* @return
*/
private static String getRandomFileName() {
// 获取随机的5位数
int rannum = random.nextInt(89999) + 10000;
String nowTimestr = sDateFormate.format(new Date());
return nowTimestr + rannum;
}
}
- 创建一个路径PathUtil类,获取存放图片的路径
package com.imooc.o2o.util;
public class PathUtil {
// 获取系统分隔符
private static String separator = System.getProperty("file.separator");
public static String getImgBasePath() {
// 根据不同的系统去选择根路径
String os = System.getProperty("os.name");
String basePath = "";
if (os.toLowerCase().startsWith("win")) {
basePath = "F/project/image";
} else {
basePath = "home/cuzz/image";
}
basePath = basePath.replace("/", separator);
return basePath;
}
public static String getShopImagePath(long shopId) {
String imagePath = "/upload/item/shop" + shopId + "/";
return imagePath.replace("/", separator);
}
}
Dto之ShopExecution的实现
数据传输对象(DTO)(Data Transfer Object),是一种设计模式之间传输数据的软件应用系统。数据传输目标往往是数据访问对象从数据库中检索数据。数据传输对象与数据交互对象或数据访问对象之间的差异是一个以不具有任何行为除了存储和检索的数据(访问和存取器)
- ShopExecution
package com.imooc.o2o.dto;
import com.imooc.o2o.enmus.ShopStateEnum;
import com.imooc.o2o.entity.Shop;
import java.util.List;
public class ShopExecution {
// 结果状态
private int state;
// 状态标识
private String stateInfo;
// 店铺数量
private int count;
// 返回的shop列表
private List shopList;
// 操作的shop(增删改查的时候用到)
private Shop shop;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getStateInfo() {
return stateInfo;
}
public void setStateInfo(String stateInfo) {
this.stateInfo = stateInfo;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public List getShopList() {
return shopList;
}
public void setShopList(List shopList) {
this.shopList = shopList;
}
public Shop getShop() {
return shop;
}
public void setShop(Shop shop) {
this.shop = shop;
}
// 无参构造器
public ShopExecution() {
}
// 操作失败有参构造器
public ShopExecution(ShopStateEnum stateEnum) {
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
}
// 成功的有参构造器
public ShopExecution(ShopStateEnum stateEnum, Shop shop) {
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
this.shop = shop;
}
// 成功的有参构造器2
public ShopExecution(ShopStateEnum stateEnum, List shopList) {
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
this.shopList = shopList;
}
}
- 同时我们需要一个枚举类型
package com.imooc.o2o.enmus;
public enum ShopStateEnum {
CHECK(0,"审核中"),
OFFLINE(-1, "非法商铺"),
SUCCESS(1, "操作成功"),
PASS(2, "通过认证");
private int state;
private String stateInfo;
ShopStateEnum(int state, String stateInfo) {
this.state = state;
this.stateInfo = stateInfo;
}
public int getState() {
return state;
}
public String getStateInfo() {
return stateInfo;
}
/**
* 依据传入的state返回相应的enum值
*/
public static ShopStateEnum stateOf(int state) {
for (ShopStateEnum stateEnum : values()) {
if (stateEnum.getState() == state) {
return stateEnum;
}
}
return null;
}
}
店铺注册之service层
- 新建shopService接口
package com.imooc.o2o.service;
import com.imooc.o2o.dto.ShopExecution;
import com.imooc.o2o.entity.Shop;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
public interface ShopService {
ShopExecution addShop(Shop shop, CommonsMultipartFile shopImg);
}
- 先封装一些RuntimeExpection
这样的好处是知道错误类型,出错的就知道是店铺相关的错误
package com.imooc.o2o.exceptiopns;
public class ShopOperationException extends RuntimeException {
public ShopOperationException(String msg) {
super(msg);
}
}
- 实现类
package com.imooc.o2o.service.impl;
import com.imooc.o2o.dao.ShopDao;
import com.imooc.o2o.dto.ShopExecution;
import com.imooc.o2o.enmus.ShopStateEnum;
import com.imooc.o2o.entity.Shop;
import com.imooc.o2o.exceptiopns.ShopOperationException;
import com.imooc.o2o.service.ShopService;
import com.imooc.o2o.util.ImageUtil;
import com.imooc.o2o.util.PathUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import java.util.Date;
@Service
public class ShopServiceImpl implements ShopService{
@Autowired
private ShopDao shopDao;
@Override
// 事务的支持
@Transactional
public ShopExecution addShop(Shop shop, CommonsMultipartFile shopImg) {
// 空值判断
if (shop == null) {
return new ShopExecution(ShopStateEnum.NULL_SHOP);
}
try {
// 给店铺信息赋值初始值
shop.setEnableStatus(0);
shop.setCreateTime(new Date());
shop.setLastEditTime(new Date());
// 添加店铺信息
int effectedNum = shopDao.insertShop(shop);
// 判断是否插入成功
if (effectedNum <= 0) {
throw new ShopOperationException("店铺创建失败");
} else {
if (shopImg != null) {
// 存储图片
try {
addShopImg(shop, shopImg);
} catch (Exception e) {
throw new ShopOperationException("addShopImg error" + e.getMessage());
}
// 更新图片信息
effectedNum = shopDao.updateShop(shop);
if (effectedNum <= 0) {
throw new ShopOperationException("更新图片地址失败");
}
}
}
} catch (Exception e) {
throw new ShopOperationException("addShop error" + e.getMessage());
}
return new ShopExecution(ShopStateEnum.CHECK, shop);
}
private void addShopImg(Shop shop, CommonsMultipartFile shopImg) {
// 获取shop图片目录的相对值路径
String dest = PathUtil.getShopImagePath(shop.getShopId());
String shopImgAddr = ImageUtil.generateThumbnail(shopImg, dest);
shop.setShopImg(shopImgAddr);
}
}
Controller层
- 新建一个ShopAdminController类
package com.imooc.o2o.web.shopadmin;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping(value = "shop", method = RequestMethod.GET)
public class ShopAdminController {
@RequestMapping(value="/shopoperation")
public String shopOperation() {
return "shop/shopedit";
}
}
-
效果图
- 添加shopoperation.js文件
$(function () {
// 获取初始url
var initUrl = "/project2/shop/getshopinitinfo";
var registerShopUrl = "/project2/shop/registershop";
alert(initUrl);
getShopInitInfo();
function getShopInitInfo(){
// 获取初始值
$.getJSON(initUrl, function (data) {
alert("SSSSSSSS");
if (data.success) {
var tempHtml = "";
var tempAreaHtml = "";
data.shopCategoryList.map(function (item, index) {
tempHtml += "";
});
data.areaList.map(function (item, index) {
tempAreaHtml += "";
});
$("#shop-category").html(tempHtml);
$("#area").html(tempAreaHtml);
}
});
}
// 提交
$("#submit").click(function () {
var shop = {};
shop.shopName = $("#shop-name").val();
shop.shopAddr = $("#shop-addr").val();
shop.phone = $("#phone").val();
shop.shopDesc = $("#shop-desc").val();
shop.shopCategory = {
shopCategoryId:$("#shop-category").find("option").not(function () {
return !this.selected;
}).data("id")
};
shop.area = {
areaId: $("#area").find("option").not(function () {
return !this.selected;
}).data("id")
};
var shopImg = $("#shop-img")[0].file[0];
var formData = new FormData();
formData.append("shopImg", shopImg);
formData.append("shopStr", JSON.stringify(shop));
var verifyCodeActual = $("#j_captcha").val();
// 判断是否为空
if (!verifyCodeActual) {
$.toast("请输入验证码!");
return;
}
formData.append("verifyCodeActual", verifyCodeActual);
// 提交到后台
$.ajax({
url: registerShopUrl,
type: "POST",
data: formData,
contentType: false,
processDate: false,
cache: false,
success: function (data) {
if (data.success){
$.toast("提交成功!");
} else {
$.toast("提交失败" + data.errMsg);
}
// 不管没有提交成功 都更换验证码
$("#captcha_img").click();
}
});
});
});
- 新建一个管理类,通过json数据
package com.imooc.o2o.web.shopadmin;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imooc.o2o.dto.ShopExecution;
import com.imooc.o2o.enmus.ShopStateEnum;
import com.imooc.o2o.entity.Area;
import com.imooc.o2o.entity.PersonInfo;
import com.imooc.o2o.entity.Shop;
import com.imooc.o2o.entity.ShopCategory;
import com.imooc.o2o.service.AreaService;
import com.imooc.o2o.service.ShopCategoryService;
import com.imooc.o2o.service.ShopService;
import com.imooc.o2o.util.HttpServletRequestUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/shop")
public class ShopManagementController {
@Autowired
private ShopService shopService;
@Autowired
private ShopCategoryService shopCategoryService;
@Autowired
private AreaService areaService;
@RequestMapping(value = "/getshopinitinfo", method = RequestMethod.GET)
@ResponseBody
private Map getShopInitInfo() {
Map modelMap = new HashMap<>();
List shopCategoryList = new ArrayList<>();
List areaList = new ArrayList<>();
try{
shopCategoryList = shopCategoryService.getShopCategoryList(new ShopCategory());
areaList = areaService.getAreaList();
modelMap.put("shopCategoryList", shopCategoryList);
modelMap.put("areaList", areaList);
modelMap.put("success", true);
} catch (Exception e) {
modelMap.put("success", false);
modelMap.put("errMsg", e.getMessage());
}
return modelMap;
}
@RequestMapping(value = "/registershop", method = RequestMethod.POST)
@ResponseBody
private Map registerShop(HttpServletRequest request) {
Map modelMap = new HashMap<>();
// 1. 接受并转化相应的参数, 包括店铺信息以及图片信息
String shopstr = HttpServletRequestUtil.getString(request, "shopStr");
ObjectMapper mapper = new ObjectMapper();
Shop shop = null;
try{
shop = mapper.readValue(shopstr, Shop.class);
} catch (Exception e) {
modelMap.put("success", false);
modelMap.put("errMsg", e.getMessage());
return modelMap;
}
CommonsMultipartFile shopImg = null;
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
if (commonsMultipartResolver.isMultipart(request)) {
MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
shopImg = (CommonsMultipartFile) multipartHttpServletRequest.getFile("shopImg");
} else {
modelMap.put("success", false);
modelMap.put("errMsh", "上传图片不能为空");
return modelMap;
}
// 2. 注册店铺
if (shop != null && shopImg != null) {
PersonInfo owner = new PersonInfo();
owner.setUserId(1L);
shop.setOwner(owner);
ShopExecution shopExecution = null;
try {
shopExecution = shopService.addShop(shop, shopImg.getInputStream(), shopImg.getOriginalFilename());
} catch (IOException e) {
e.printStackTrace();
}
if (shopExecution.getState() == ShopStateEnum.CHECK.getState()) {
modelMap.put("success", true);
} else {
modelMap.put("success", false);
}
return modelMap;
} else {
modelMap.put("success", false);
modelMap.put("errMsh", "请输入店铺信息");
return modelMap;
}
// 3. 返回结果
}
}
-
获取到结果
验证码工具包
- 拷贝依赖文件到pom.xml中
http://mvnrepository.com/artifact/com.github.penggle/kaptcha/2.3.2 - 在web.xml中,定义样式
Kaptcha
com.google.code.kaptcha.servlet.KaptchaServlet
kaptcha.border
no
kaptcha.textproducer.font.color
red
kaptcha.image.width
135
kaptcha.textproducer.char.string
ACDEFHKPRSTWX345679
kaptcha.image.height
50
kaptcha.textproducer.font.size
43
kaptcha.noise.color
black
kaptcha.textproducer.char.length
4
kaptcha.textproducer.font.names
Arial
Kaptcha
/Kaptcha
function changeVerifyCode(img) {
img.src = "../Kaptcha?" + Math.floor(Math.random() * 100);
}
- 把验证码传入Json
var verifyCodeActual = $("#j_captcha").val();
// 判断是否为空
if (!verifyCodeActual) {
$.toast("请输入验证码!");
return;
}
formData.append("verifyCodeActual", verifyCodeActual);
-
就有了验证码
- 验证码util
package com.imooc.o2o.util;
import javax.servlet.http.HttpServletRequest;
public class CodeUtil {
public static boolean checkVerifyCode(HttpServletRequest request) {
String verifyCodeExpected = (String) request.getSession().getAttribute(
com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
String verifyCodeActual = HttpServletRequestUtil.getString(request,
"verifyCodeActual");
if (verifyCodeActual == null
|| !verifyCodeActual.equalsIgnoreCase(verifyCodeExpected)) {
return false;
}
return true;
}
}
-
测试
可以看出数据库中插入了数据