考勤系统

店家管理系统开发1

2018-06-21  本文已影响0人  shenyoujian

店家管理系统开发
店铺注册:


image.png

自下而上的实现店铺的注册功能:
1、在Dao层下创建一个ShopDao接口
增加店铺,1为增加成功,-1为增加失败


image.png
因为Dao层的实现类是由mybatis实现的,所以我们需要在mapper文件夹下创建一个ShopDao.xml配置文件。

junit测试

然后运行run test这里报错原因是shopDao没有注入进来,原因是我们的ShopDaoTest没有继承BaseTest类,继承了就行了。

更新店铺信息

在dao层的ShopDao创建更新方法


image.png

mybatis的优势动态生成sql语句
为什么要动态生成呢?假如我们某一张表里面只有两列a和b,做更新的时候有时候只需要更新a而不需要更新b,有时候只要更新b而不需要更细a,有时候两者都需要去做更新,如果不支持动态语句的话就需要写三条update语句才能满足数据的更新,如果支持动态sql就只要写一个方法就可以了。
不能更新的字段:
shop_id,owner_id(一旦你的店铺的用户确定了就不能更新了),create_time也是不变的,其他字段都是可变的。

junit测试

在shopDaoTest里

image.png

<if test="shopName!=null">shop_name=#{shopName},</if>
注意其中的shopName是成员变量,shop_name是数据库字段。

运行之后就可以看到数据库里的修改了。

Thumbnailator图片处理和封装Util

image.png
image.png

然后在util包下创建一个ImageUtil类来封装thumbnailator方法的,
测试thumbanailator包下方法,首先在resources下存放一张watermark.jgp水印,并且在任意位置存放一张xiaohuangren的图片,目的就是要通过使用thumbanailator包下的方法来处理xiaohuangren图片的大小并且打上水印。


image.png image.png
image.png

运行之后


image.png

因为thumbnailator主要是需要告诉它输入的文件是什么以及输出的文件是什么这其中也就涉及到了地址的处理,所以需要提前编写一个地址工具类,在util下创建一个PathUtil类,这个类主要提供两类的路径,一类是根据执行环境的不同提供根路径,根路径就是我们项目的所有图片需要存放的路径,因为我们是工具类,不用去new它所以设置为静态方法,


image.png

获取店铺图片的存储路径,因为这些图片存储在各自店铺的路径下,所以传入一个店铺id。


image.png

回到ImageUtil去编写缩略图方法

package com.imooc.o2o.util;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

import javax.imageio.ImageIO;

import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;

public class ImageUtil {
    private static String basePath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
    // 定义时间格式和随机对象
    private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
    private static final Random r = new Random();

    // 处理缩略图也就是门面照以及商品的小图,由于这个方法处理的是用户传递过来的文件
    // 也就是用户传递过来的文件流,因此传入的参数就是spring自带的文件处理对象
    // 同时还需要接收一个我们将这个文件保存在哪里
    public static String generateThumbnail(File thumbnail, String targetAddr) {
        // 用户传递过来的文件名是随意命名的,有很多是重名的,所以我们不要用它的名字
        // 用我们系统自己随机生成的文件名
        String realFileName = getRandomFileName();
        // 获取用户上传过来的扩展名,例如jpg,png等
        String extension = getFileExtension(thumbnail);
        // 随机名和扩展名就构成了新文件的新名字然后保存在targetAddr下
        // 但是这个路径有时是不存在的,所以需要先创建
        makeDirPath(targetAddr);
        // 所以该文件的相对路径
        String relativeAddr = targetAddr + realFileName + extension;
        // 最后的文件绝对路径就是由根路径和相对路径来组成
        File dest = new File(PathUtil.getImgBasePath() + relativeAddr);
        // 开始创建缩略图,就是把用户传过来的文件变小
        try {
            Thumbnails.of(thumbnail).size(200, 200)
                    .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "right.gif")), 0.25f)
                    .outputQuality(0.8f).toFile(dest);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return targetAddr;

    }

    /**
     * 创建目标路径所涉及到的目录,即/home/work/xiangze/xxx.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(File thumbnail) {
        String originalFileName = thumbnail.getName();
        return originalFileName.substring(originalFileName.lastIndexOf("."));
    }

    /**
     * 生成随机文件名,当前年月日小时分钟秒钟+五位随机数
     * 
     * @return
     */
    private static String getRandomFileName() {
        // 获取随机的五位数
        int rannum = r.nextInt(89999) + 10000;
        String nowTimeStr = sDateFormat.format(new Date());
        return nowTimeStr + rannum;
    }

    public static void main(String[] args) throws IOException {
        // of传入需要处理的相关文件
        // size指定图片大小,watermark添加水印,第一个参数是水印的位置(右下角)
        // 第二个是水印的路经,由于我们的水印图片是保存在classpath路径下的
        // 因此需要获取classpath的绝对值路径,由于我们的方法是通过线程去执行的,
        // 因此我们可以通过线程去逆推到它的类加载器,从而得到资源的绝对路径
        // 第三个参数为透明度0.25f
        // 最后压缩80%
        // 最后输出的路径
        Thumbnails.of(new File("C:/Users/ljs/Pictures/Camera Roll/default.jpg")).size(200, 200)
                .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "right.gif")), 0.25f)
                .outputQuality(0.8f).toFile("C:/Users/ljs/Pictures/Camera Roll/defaultnew.jpg");

    }

}

编写好枚举类之后再回到dto的shopexecution下去编写

package com.imooc.o2o.dto;

import java.util.List;

import com.imooc.o2o.entity.Shop;
import com.imooc.o2o.enums.ShopStateEnum;

public class ShopExecution {

    // 结果状态
    private int state;
    // 结果标识
    private String stateInfo;
    // 店铺的数量
    private int count;

    // 操作的shop(增删改查的时候要用到)
    private Shop shop;
    // shop列表(查询店铺的时候要用到)
    private List<Shop> shopList;

    // 默认构造函数
    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;
    }

    // 店铺操作成功的时候使用的构造器
    public ShopExecution(ShopStateEnum stateEnum, List<Shop> shopList) {
        this.state = stateEnum.getState();
        this.stateInfo = stateEnum.getStateInfo();
        this.shopList = shopList;
    }

    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 Shop getShop() {
        return shop;
    }

    public void setShop(Shop shop) {
        this.shop = shop;
    }

    public List<Shop> getShopList() {
        return shopList;
    }

    public void setShopList(List<Shop> shopList) {
        this.shopList = shopList;
    }

}

service层关于店铺注册的逻辑

1、service层需要事务的管理,首先是将店铺插入到数据库中,其次是返回店铺的id,然后根据id去创建出存储图片的文件夹,在这个文件夹下面去存储我们的图片,最后再把文件夹的地址更新回这条数据里面去。这样就需要四个步骤去执行,其中任何一条出错就需要回滚,所以事务就非常必要了。
2、创建ShopService的接口

package com.imooc.o2o.service;

import java.io.File;


import com.imooc.o2o.dto.ShopExecution;
import com.imooc.o2o.entity.Shop;

public interface ShopService {
    ShopExecution addShop(Shop shop, File shopImg);
}

3、创建ShopServiceImpl实现接口
3.1、首先检查传入的shop是否为空,为空抛出异常,这里的NULL_SHOP在之前的枚举类没有定义,先去定义


image.png

3.2、除了判断shop是否为空还要判断shop的关联area,shopcategory等是否为空,
4、添加事务的标签
5、添加店铺的步骤,因为这些步骤有可能出错,所以写在try catch中
5.1初始化必要的参数
5.2添加店铺的信息(注入ShopDao)
5.3判断添加是否有效
6、为什么是抛出runtimeexception而不是exception原因是只有抛出runtimeexception事务才会终止并回滚,
7、添加成功后就去判断shopImg是否为空,不为空就存储到相关的目录里面,
7.1addshopimg方法需要两个参数,一个shop因为需要shopid去创建图片的目录,还有一个是shopimg这个文件流去存储到相关的目录里面。存储成功之后,addshopimg这个方法就会将生成好的图片地址给更新到shop实体类里面去。
7.2得到图片的地址
题外话:对于java的所有方法来说,它的参数都是值传递形式传递到函数里面去。对于基本类型来说它传递的是基本类型的字面量的拷贝,在函数内对这个值得改变是影响不了外面的,如果参数是引用类型的话,它传递的是参数所引用对象堆中地址值的拷贝,所以在方法内对它改变是能影响到外面的。所以shop在addshopimg方法中更新了图片的地址,我们在外面是可以取到的。
8.更新店铺的图片地址
9、实现addshopImg方法
9.1、获取shop图片目录的相对值路径
10、最后再将addShop方法返回ShopExecution(ShopStateEnum.CHECK, shop);成功的信息

package com.imooc.o2o.service.impl;

import java.io.File;
import java.util.Date;

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

import com.imooc.o2o.Exceptions.ShopOperationException;
import com.imooc.o2o.dao.ShopDao;
import com.imooc.o2o.dto.ShopExecution;
import com.imooc.o2o.entity.Shop;
import com.imooc.o2o.enums.ShopStateEnum;
import com.imooc.o2o.service.ShopService;
import com.imooc.o2o.util.ImageUtil;
import com.imooc.o2o.util.PathUtil;

@Service
public class ShopServiceImpl implements ShopService {

    @Autowired
    private ShopDao shopDao;

    @Transactional
    @Override
    public ShopExecution addShop(Shop shop, File shopImg) {
        // 空值判断
        if (shop == null) {
            return new ShopExecution(ShopStateEnum.NULL_SHOP);
        }
        if (shop.getArea() == null) {
            return new ShopExecution(ShopStateEnum.NULL_SHOP);
        }
        if (shop.getOwner() == null) {
            return new ShopExecution(ShopStateEnum.NULL_SHOP);
        }
        if (shop.getShopCategory() == 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("shopaddImg 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, File shopImg) {
        // 获取shop图片目录的相对值路径
        String dest = PathUtil.getShopImgPath(shop.getShopId());
        String shopImgAddr = ImageUtil.generateThumbnail(shopImg, dest);
        shop.setShopImg(shopImgAddr);
    }

}

11这里抛出的异常都是runtimeexception,其实并不是规范的写法,规范的写法是在创建一个exceptions package里面封装的是我们业务的异常,
这样只是对Runtimeexception做了一层很薄的封装,这样子做的意义在于我们看到ShopOperationException异常的时候能够知道是跟店铺相关的。


image.png

12最后把service层的addShop方法里的RuntimeException替换成这个就行了。

对addShop进行单元测试

public class ShopDaoTest extends BaseTest {
    @Autowired
    private ShopDao shopDao;
    
    @Test
    @Ignore
    public void testInsertShop() {
        Shop shop = new Shop();
        PersonInfo owner = new PersonInfo();
        ShopCategory shopCategory = new ShopCategory();
        Area area = new Area();
        owner.setUserId(1L);
        area.setAreaId(2L);
        shopCategory.setShopCategoryId(1L);
        shop.setArea(area);
        shop.setOwner(owner);
        shop.setShopCategory(shopCategory);
        shop.setShopName("测试的店铺");
        shop.setShopAddr("test");
        shop.setShopDesc("test");
        shop.setShopImg("test");
        shop.setPhone("test");
        shop.setAdvice("审核中");
        shop.setEnableStatus(1);
        shop.setCreateTime(new Date());
        int effectedNum = shopDao.insertShop(shop);
        assertEquals(1, effectedNum);
    }
    
    @Test
    public void testUpdateShop() {
        Shop shop = new Shop();
        shop.setShopId(1L);
        shop.setShopAddr("测试地址");
        shop.setShopDesc("测试描述");
        shop.setLastEditTime(new Date());
        int effectedNum = shopDao.updateShop(shop);
        assertEquals(1, effectedNum);
    }
    

可以看到生成了图片数据库也添加了。

实现controller层
1、导入jar包,将实体类转换为json,将json转换为实体类


image.png

2、实现工具类,解析request里面参数。所以在util package下创建一个


image.png
package com.imooc.o2o.util;

import javax.servlet.http.HttpServletRequest;

/**
 * 负责HttpServletRequest请求的参数
 * @author ljs
 *
 */
public class HttpServletRequestUtil {
    //把请求参数里的字符串转换为整数
    public static int getInt(HttpServletRequest request, String key) {
        try {
            return Integer.decode(request.getParameter(key));
        }catch(Exception e) {
            return -1;
        }
    }
    
    public static Long getLong(HttpServletRequest request, String key) {
        try {
            return Long.valueOf(request.getParameter(key));
        }catch(Exception e) {
            return -1L;
        }
    }
    
    public static Double getDouble(HttpServletRequest request, String key) {
        try {
            return Double.valueOf(request.getParameter(key));
        }catch(Exception e) {
            return -1d;
        }
    }
    
    public static Boolean getBoolean(HttpServletRequest request, String key) {
        try {
            return Boolean.valueOf(request.getParameter(key));
        }catch(Exception e) {
            return false;
        }
    }
    
    public static String getString(HttpServletRequest request, String key) {
        try {
            String result = request.getParameter(key);
            if(result!=null) {
                result = result.trim();
            }
            if("".equals(result)) {
                result = null;
            }
            return result;
        }catch(Exception e) {
            return null;
        }
    }
}

3、在web层创建shopadmin package,管理后台的相关controller都在这里,
request参数代表客户端的请求。

@Controller
@RequestMapping("/shopadmin")
public class ShopManagementController {
    @ResponseBody
    @RequestMapping(value="/registershop", method=RequestMethod.GET)
    private Map<String, Object> registerShop(HttpServletRequest request){
        //返回值
        Map<String, Object> modelMap = new HashMap<String, Object>();
        //1、接收前端传过来的Shop字符串信息,包括店铺信息以及图片信息,并转换为shop实体类
        //shopStr是跟前端约定好的key值
        String shopStr = HttpServletRequestUtil.getString(request, "shopStr");
        //接收完成后需要做转换
        ObjectMapper mapper = new ObjectMapper();
        //定义一个shop实体类去接收
        Shop shop = null;
        //开始转换
        try {
            shop = mapper.readValue(shopStr, Shop.class);
        }catch(Exception e) {
            //转换失败就返回modelMap,告诉前台说转换失败
            modelMap.put("success", false);
            modelMap.put("errMsg", e.getMessage());
            return modelMap;
        }
        //接收图片
        CommonsMultipartFile shopImg = null;
        //文件上传解析器,去解析request里面的文件信息
        CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(); 
        //2、注册店铺
        
        //3、返回结果
        
        
    }
}

上一篇 下一篇

猜你喜欢

热点阅读