1、创建接口返回结果类BaizhanResult,匹配接口文档返回数据
@Data
public class BaizhanResult implements Serializable {
private int status;
private String msg;
private Object data;
public static BaizhanResult ok(){
BaizhanResult br = new BaizhanResult();
br.setMsg("OK");
br.setStatus(200);
return br;
}
public static BaizhanResult ok(Object data){
BaizhanResult br = new BaizhanResult();
br.setMsg("OK");
br.setStatus(200);
br.setData(data);
return br;
}
public static BaizhanResult error(String msg){
BaizhanResult br = new BaizhanResult();
br.setMsg(msg);
br.setStatus(400);
return br;
}
}
接口1:规格参数查询
依次创建service,mapper(已创建),serviceImpl层,控制层controller
// service层
public interface ItemParamService {
BaizhanResult selectAllItemParams();
}
// mapper层
@Mapper
@Component
public interface TbItemParamMapper extends BaseMapper<TbItemParam> {
}
@Service
public class ItemParamServiceImpl implements ItemParamService {
@Autowired
private TbItemParamMapper itemParamMapper;
/**
* 查询所有规格参数
* 注意: 异常处理问题。
* @return
*/
@Override
public BaizhanResult selectAllItemParams() {
try {
// selectList 有条件查询多行数据。参数是条件。
// 需要的是无条件查询所有。
List<TbItemParam> result = itemParamMapper.selectList(null);
return BaizhanResult.ok(result);
}catch (Exception e){
throw new DaoException("查询规格参数错误", e);
}
}
}
控制层
@RestController
/**
*@RestController相当于@Controller+@ResponseBody两个注解
*@ResponseBody 表示该方法的返回结果直接写入 HTTP response body 中,一般在异步获取数据时使用【也就是AJAX】,在使用 *@RequestMapping后,返回值通常解析为跳转路径,但是加上 @ResponseBody 后返回结果不会被解析为跳转路径,而是直接写入 HTTP *response body 中。 比如异步获取 json 数据,加上 @ResponseBody 后,会直接返回 json 数据。
*/
@Slf4j
public class ItemParamController {
@Autowired
private ItemParamService itemParamService;
/**
* 查询所有的规格参数。
* 访问数据库表格tb_item_param。
* @return BaizhanResult - 自定义的返回结果类型。
* 包含属性: status - 状态编码; msg - 返回字符串消息; data - 返回数据对象。
*/
@GetMapping("/backend/itemParam/selectItemParamAll")
public BaizhanResult selectAllItemParams(){
try {
log.info("查询规格参数");
return itemParamService.selectAllItemParams();
}catch (DaoException e){
log.error("查询规格参数错误:" + e.getMessage());
return BaizhanResult.error("服务器忙,请稍后重试");
}
}
}
接口2:根据父类目查询所有子类目
后面只记serviceImpl和controller的处理方法
这里返回的数据,需要新增一个“leaf”状态
所以需要新写一个接受类
/**
* 当前系统中需要使用的商品类型值对象。value object
* 只在当前系统中使用。且用于传递数据使用。
* 不于数据库有任何关联。
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TbItemCatVO extends TbItemCat {
// 编写推导属性。
public Boolean getLeaf(){
return !getIsParent();
}
public void setLeaf(Boolean leaf){
// 推导属性,不需要考虑赋值。
// jackson要求,类型中除class以外的所有属性,必须成对
// 提供getter/setter
}
}
impl实现类,注意 有条件查询多行数据。条件统一为QueryWrapper类型,参数第一个是字符串类型,代表具体的数据库表格字段名。不是属性名。第二个参数类型是Object。是查询条件值
@Service
public class ItemCategoryServiceImpl implements ItemCategoryService {
@Autowired
private TbItemCatMapper itemCatMapper;
/**
* 根据父商品类型主键,查询子商品类型集合。
* @param id
* @return
*/
@Override
public BaizhanResult selectItemCategoriesByParentId(Long id) {
try {
// 有条件查询多行数据。条件统一为QueryWrapper类型,
// 条件的泛型就是要查询的实体类型。
QueryWrapper<TbItemCat> queryWrapper =
new QueryWrapper<>();
// QueryWrapper 用于封装所有要查询的条件。创建对象不做任何配置
// 相当于无条件全数据查询。
// 所有的条件都是基于QueryWrapper中的方法实现的。
// 方法名称,和具体条件相关。如: 等值 eq。 大于 gt。 大于等于 ge。小于 lt。小于等于 le
// 所有的方法参数都是2个。
// 第一个是字符串类型,代表具体的数据库表格字段名。不是属性名。
// 第二个参数类型是Object。是查询条件值
// 多条件and并列,则直接多条件设置即可。
queryWrapper.eq("parent_id", id)
.eq("status", 1);
List<TbItemCat> result = itemCatMapper.selectList(queryWrapper);
// 创建一个转换后的结果集合
List<TbItemCatVO> localResult = new ArrayList<>(result.size());
for(TbItemCat itemCat : result ){
// 创建子类型对象。
TbItemCatVO vo = new TbItemCatVO();
// 把查询结果对象中的每个属性的值,赋值到vo对象中。
// vo.setId(itemCat.getId());
// Spring提供的属性赋值工具。根据getter和setter,赋值属性。
// 把源itemCat中的属性,赋值到目标vo中。
// 同名赋值,同名属性类型也相同。相当于 vo.setId(itemCat.getId());
BeanUtils.copyProperties(itemCat, vo);
// 根据是否为父节点来设置leaf
vo.setLeaf(!itemCat.getIsParent());
localResult.add(vo);
}
return BaizhanResult.ok(localResult);
}catch (Exception e){
throw new DaoException("根据父商品类型主键,查询子商品类型集合错误", e);
}
}
}
注意点:1、queryWrapper作条件查询,常用eq、gt等,而queryWrapper又作为mapper语句的条件
2、复制对象属性 BeanUtils.copyProperties
3、根据是否为父节点来设置额外leaf
4、itemCatMapper.selectList 返回符合queryWrapper条件的列表
接口3:判断商品分类是否已经添加过规格参数
impl层
/**
* 根据商品分类主键,查询规格
* @param itemCatId
* @return
*/
@Override
public BaizhanResult selectHaveByItemCatId(Long itemCatId) {
try {
// 根据条件查询一行数据。
// 查询条件还是QueryWrapper
QueryWrapper<TbItemParam> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("item_cat_id", itemCatId);
// 查询有结果,返回具体对象,查询无结果,返回null。查询结果行数>1,抛出异常。
TbItemParam itemParam = itemParamMapper.selectOne(queryWrapper);
if (itemParam == null) {
// 无对应的规格,可以新增规格参数
return BaizhanResult.ok();
}
return BaizhanResult.error("商品分类有对应规格参数,请选择其他商品分类");
}catch (Exception e){
throw new DaoException("根据商品分类主键,检查是否存在规格参数时,错误", e);
}
}
控制层
/**
* 根据商品类型主键,查询规格参数
* 对应商品类型有规格参数数据,返回错误结果, status = 400
* 反之,返回正确结果,status = 200
* @param itemCatId 商品类型主键。
* @return
*/
@GetMapping("/backend/itemParam/selectHaveParam")
public BaizhanResult selectHaveByItemCatId(Long itemCatId){
try {
log.info("根据商品类型主键,查询规格参数");
return itemParamService.selectHaveByItemCatId(itemCatId);
}catch (Exception e){
log.error(e.getMessage());
return BaizhanResult.error("商品分类存在规格参数,请选择其他商品分类");
}
}
注意:1、itemParamMapper.selectOne 查询是否有一个
接口4:规格参数添加
前端传过来item_cat_id,param_data,所以还差商品id,创建时间created 和 更新时间updated
impl
/**
* 新增规格参数到数据库
* @param itemParam
* @return
*/
@Override
@Transactional(rollbackFor = {DaoException.class})
public BaizhanResult insertItemParam(TbItemParam itemParam) {
try {
// 维护要新增数据的完整性
itemParam.setId(IDUtils.genItemId()); // 生成主键
Date now = new Date(); // 创建时间
itemParam.setCreated(now);
itemParam.setUpdated(now); // 更新时间,新增数据的更新时间就是创建时间.
// 新增数据到数据库,返回新增数据的行数
int status = itemParamMapper.insert(itemParam);
if (status != 1) {
// 新增错误
throw new DaoException("新增规格参数错误");
}
return BaizhanResult.ok();
}catch (DaoException e){
// 自定义抛出的异常.
throw e;
}catch (Exception e){
// mapper访问数据库发生的其他异常.
throw new DaoException("新增规格参数到数据库时,发生异常:" + e.getMessage(), e);
}
}
注意:1、工具类IDUtils.genItemId() 用于生成商品id,工具类由架构师提供的
/**
* 商品id生成
*/
public static long genItemId() {
//取当前时间的长整形值包含毫秒
long millis = System.currentTimeMillis();
//long millis = System.nanoTime();
//加上两位随机数
Random random = new Random();
int end2 = random.nextInt(99);
//如果不足两位前面补0
String str = millis + String.format("%02d", end2);
long id = new Long(str);
return id;
}
2、Date now = new Date()生成时间对象
3、itemParamMapper.insert(itemParam) 返回状态整数
4、使用@Transactional注解来管理事务
控制层
/**
* 新增规格参数到数据库
* @param itemParam 要新增的数据
* @return
*/
@PostMapping("/backend/itemParam/insertItemParam")
public BaizhanResult insertItemParam(TbItemParam itemParam){
try {
log.info("新增规格参数到数据库:" + itemParam.toString());
return itemParamService.insertItemParam(itemParam);
}catch (Exception e){
log.error(e.getMessage());
return BaizhanResult.error("服务器忙,请稍后重试");
}
}
接口5:规格参数删除
impl
/**
* 根据主键,删除规格参数.
* @param id
* @return
*/
@Override
@Transactional(rollbackFor = {DaoException.class})
public BaizhanResult deleteItemParamById(Long id) {
try {
// 删除使用的方法是delete系列方法
int rows = itemParamMapper.deleteById(id);
if (rows != 1) {
throw new DaoException("删除规格参数错误");
}
return BaizhanResult.ok();
}catch (DaoException e){
throw e;
}catch (Exception e){
throw new DaoException("从数据库删除规格参数时发生错误:" + e.getMessage(), e);
}
}
kongzhiceng
/**
* 删除规格参数
*/
@GetMapping("/backend/itemParam/deleteItemParamById")
public BaizhanResult deleteItemParamById(Long id){
try {
log.info("删除规格参数:"+id);
return itemParamService.deleteItemParamById(id);
}catch (Exception e){
log.error(e.getMessage());
return BaizhanResult.error("服务器忙,请稍后重试");
}
}
接口6:查询商品列表接口
impl
/**
* 分页查询,表格 tb_item
* @param page
* @param rows
* @return
*/
@Override
public BaizhanResult selectItemsByPage(int page, int rows) {
try {
// IPage<查询结果泛型> selectPage(IPage<查询结果泛型> 分页条件, QueryWrapper 查询条件)
// IPage接口中,定义了若干方法,可以获取分页查询的总计数据行数,页数,当前页数据集合等。
IPage<TbItem> iPage = new Page<>(page, rows);
IPage<TbItem> resultPage = itemMapper.selectPage(iPage, null);
List<TbItem> list = resultPage.getRecords(); // 当前页数据集合
// resultPage.getSize(); // 每页多少行数据
long total = resultPage.getTotal(); // 总计多少行数据
// resultPage.getPages(); // 总计多少页
// resultPage.getCurrent(); // 当前第几页
// 使用Map传递最终查询结果
Map<String, Object> result = new HashMap<>();
result.put("total", total);
result.put("result", list);
return BaizhanResult.ok(result);
}catch (Exception e){
throw new DaoException("分页查询商品时,发生错误:"+ e.getMessage(), e);
}
}
注意:1、IPage泛型,也可以使用Page,参数是(页数,行数)
2、itemMapper.selectPage,参数(IPage,querywrapper),返回数据结果 IPage类型
3、由于返回结果需要的是一个data,没有封装新的实体类的话,用map传递键值对数据
控制层
/**
* 分页查询商品
* @return
*/
@GetMapping("/backend/item/selectTbItemAllByPage")
public BaizhanResult selectItemsByPage(@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int rows){
try {
log.info("分页查询商品,第" + page + "页,每页" + rows + "行");
return itemService.selectItemsByPage(page, rows);
}catch (Exception e){
log.error(e.getMessage());
return BaizhanResult.error("服务器忙,请稍后重试");
}
}
注意:1、@RequestParam 为请求参数注解,Get请求访问时:
- 不加@RequestParam注解:url可带参数也可不带参数,输入 localhost:8080/list1 以及 localhost:8080/list1?userId=xxx 方法都能执行;
- 加@RequestParam注解:url必须带有参数。也就是说你直接输入localhost:8080/list2 会报错,不会执行方法。只能输入localhost:8080/list2?userId=xxx 才能执行相应的方法
接口7:图片上传接口
impl
/**
* 文件上传微服务,服务实现类型
*/
@Service
public class FileuploadServiceImpl implements FileuploadService {
// 把application-commonspojo中的配置注入到当前属性
@Value("${baizhan.fastdfs.nginx}")
private String nginxServer;
@Override
public BaizhanResult uploadFile(MultipartFile file) {
// 调用工具的上传文件方法
try {
String[] result =
FastDFSClient.uploadFile(file.getInputStream(),
file.getOriginalFilename());
if(result == null){
throw new RuntimeException("上传文件工具类发生错误");
}
String path = nginxServer + result[0] + "/" + result[1];
return BaizhanResult.ok(path);
}catch (Exception e){
throw new RuntimeException("上传图片时发生错误:" + e.getMessage(), e);
}
}
}
注意:1、上传图片到虚拟机,所以需要先开启虚拟机
connect_timeout = 10
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 8080
# 如果tracker服务器有多个,配置文件写多行
tracker_server = 192.168.137.128:22122
# tracker_server = 192.168.137.129:22122
当前包下的yml文件
server:
port: 8888
spring:
servlet:
multipart:
max-file-size: 5MB
max-request-size: 10MB
profiles:
active: commonspojo
application:
name: baizhan-uploadfile
2、commons_pojo包下properties文件 软编码配置baizhan.fastdfs.nginx
baizhan.mysql.bigad.id=89
# 开发时如果出现开发环境和上线环境不一致时使用 软编码
# 如果当前很多系统中出现调用固定的字符串时也可以使用 软编码
baizhan.fastdfs.nginx=http://192.168.137.128:8888/
3、FastDFSClient.uploadFile(file.getInputStream(), file.getOriginalFilename()) 第一个参数上传文件流,第二个参数上传图片名称(为了更好获取文件扩展名)
控制层
@RestController
@Slf4j
public class FileuploadController {
@Autowired
private FileuploadService fileuploadService;
/**
* 上传文件到FastDFS
* @return
* 图片可访问地址。
* http://stroage服务器IP:nginx端口/组名/M00/文件名
*/
@PostMapping("/file/upload")
public BaizhanResult uploadFile(MultipartFile file){
try {
log.info("上传图片到FastDFS");
return fileuploadService.uploadFile(file);
}catch (Exception e){
log.error(e.getMessage());
return BaizhanResult.error("服务器忙,请稍后重试");
}
}
}
接口8:查询商品规格参数模板
impl
/**
* 根据商品类型主键,查询规格参数
* @param itemCatId
* @return
*/
@Override
public BaizhanResult selectItemParamByItemCatId(Long itemCatId) {
try {
QueryWrapper<TbItemParam> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("item_cat_id", itemCatId);
TbItemParam itemParam = itemParamMapper.selectOne(queryWrapper);
if(itemParam!=null){
return BaizhanResult.ok(itemParam);
}
return BaizhanResult.error("服务端消息-没有查询到该模板信息");
}catch (Exception e){
throw new DaoException("根据商品类型主键-"+itemCatId+",查询规格参数错误:" + e.getMessage(), e);
}
}
其实还是拿符合条件的数据,至于数据名+数据则由前端负责消除数据,剩下数据名,就成了模板
控制层
/**
* 根据商品类型主键,查询规格参数
* @return
*/
@GetMapping("/backend/itemParam/selectItemParamByItemCatId/{itemCatId}")
public BaizhanResult selectItemParamByItemCatId(@PathVariable("itemCatId") Long itemCatId){
try {
log.info("根据商品类型主键-"+itemCatId+",查询规格参数");
return itemParamService.selectItemParamByItemCatId(itemCatId);
}catch (Exception e){
log.error(e.getMessage());
return BaizhanResult.error("服务器忙,请稍后重试");
}
}
注意:1、@GetMapping("/backend/itemParam/selectItemParamByItemCatId/{itemCatId}")中
{itemCatId}中名字无所谓,只要跟下面@PathVariable(“xxx”)对应即可