商品分类&轮播广告


因最近又被困在了OSGI技术POC,更新进度有点慢,希望大家不要怪罪哦。

上节 我们实现了登录之后前端的展示,如:



接着,我们来实现左侧分类栏目的功能。

商品分类|ProductCategory

从上图我们可以看出,商品的分类其实是有层级关系的,而且这种关系一般都是无限层级。在我们的实现中,为了效果的展示,我们仅仅是展示3级分类,在大多数的中小型电商系统中,三级分类完全足够应对SKU的分类。

需求分析

先来分析分类都包含哪些元素,以jd为例:

  • logo(logo) 有的分类文字前面会有小标
  • 分类展示主图(img_url)
  • 主标题(title)
  • 副标题/Slogan
  • 图片跳转地址(img_link_url)-- 大多数时候我们点击分类都会分类Id跳转到固定的分类商品列表展示页面,但是在一些特殊的场景,比如我们要做一个活动,希望可以点击某一个分类的主图直接定位到活动页面,这个url就可以使用了。
  • 上级分类(parent_id)
  • 背景色(bg_color)
  • 顺序(sort)
  • 当前分类级别(type)

开发梳理

在上一小节,我们简单分析了一下要实现商品分类的一些points,那么我们最好在每次拿到需求【开发之前】,对需求进行拆解,然后分解开发流程,这样可以保证我们更好的理解需求,以及在开发之前发现一部分不合理的需求,并且如果需求设计不合理的话,开发人员完全有权,也有责任告知PM。大家的终极目的都是为了我们做的产品更加合理,好用,受欢迎!

  • 首次展示,仅仅读取一级分类(Root)
  • 根据一级分类查询二三级子分类

编码实现

查询一级分类

Service实现

1.在com.liferunner.service中创建service 接口ICategoryService.java, 编写查询所有一级分类的方法getAllRootCategorys,如下:

  1. package com.liferunner.service;
  2. import com.liferunner.dto.CategoryResponseDTO;
  3. import com.liferunner.dto.SecondSubCategoryResponseDTO;
  4. import java.util.List;
  5. /**
  6. * ICategoryService for : 分类service
  7. *
  8. * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>
  9. * @since 2019/11/13
  10. */
  11. public interface ICategoryService {
  12. /**
  13. * 获取所有有效的一级分类(根节点)
  14. *
  15. * @return
  16. */
  17. List<CategoryResponseDTO> getAllRootCategorys();
  18. }

2.编写实现类com.liferunner.service.ICategoryService.java

  1. @Service
  2. @Slf4j
  3. public class CategorySericeImpl implements ICategoryService {
  4. @Autowired
  5. private CategoryMapper categoryMapper;
  6. @Override
  7. public List<CategoryResponseDTO> getAllRootCategorys() {
  8. Example example = new Example(Category.class);
  9. val conditions = example.createCriteria();
  10. conditions.andEqualTo("type", CategoryTypeEnum.ROOT.type);
  11. val categoryList = this.categoryMapper.selectByExample(example);
  12. //声明返回对象
  13. List<CategoryResponseDTO> categoryResponseDTOS = new ArrayList<>();
  14. if (!CollectionUtils.isEmpty(categoryList)) {
  15. //赋值
  16. CategoryResponseDTO dto;
  17. for (Category category : categoryList) {
  18. dto = new CategoryResponseDTO();
  19. BeanUtils.copyProperties(category, dto);
  20. categoryResponseDTOS.add(dto);
  21. }
  22. }
  23. return categoryResponseDTOS;
  24. }
  25. }

上述代码很好理解,创建tk.mybatis.mapper.entity.Example,将条件传入,然后使用通用Mapper查询到type=1的一级分类,接着将查到的对象列表转换为DTO对象列表。

Controller实现

一般情况下,此类查询都会出现在网站的首页,因此我们来创建一个com.liferunner.api.controller.IndexController,并对外暴露一个查询一级分类的接口:

  1. package com.liferunner.api.controller;
  2. import com.liferunner.service.ICategoryService;
  3. import com.liferunner.service.IProductService;
  4. import com.liferunner.service.ISlideAdService;
  5. import com.liferunner.utils.JsonResponse;
  6. import io.swagger.annotations.Api;
  7. import io.swagger.annotations.ApiOperation;
  8. import io.swagger.annotations.ApiParam;
  9. import java.util.Collections;
  10. import lombok.extern.slf4j.Slf4j;
  11. import lombok.val;
  12. import org.springframework.beans.factory.annotation.Autowired;
  13. import org.springframework.util.CollectionUtils;
  14. import org.springframework.web.bind.annotation.GetMapping;
  15. import org.springframework.web.bind.annotation.PathVariable;
  16. import org.springframework.web.bind.annotation.RequestMapping;
  17. import org.springframework.web.bind.annotation.RequestMethod;
  18. import org.springframework.web.bind.annotation.RestController;
  19. /**
  20. * IndexController for : 首页controller
  21. *
  22. * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>
  23. * @since 2019/11/12
  24. */
  25. @RestController
  26. @RequestMapping("/index")
  27. @Api(value = "首页信息controller", tags = "首页信息接口API")
  28. @Slf4j
  29. public class IndexController {
  30. @Autowired
  31. private ICategoryService categoryService;
  32. @GetMapping("/rootCategorys")
  33. @ApiOperation(value = "查询一级分类", notes = "查询一级分类")
  34. public JsonResponse findAllRootCategorys() {
  35. log.info("============查询一级分类==============");
  36. val categoryResponseDTOS = this.categoryService.getAllRootCategorys();
  37. if (CollectionUtils.isEmpty(categoryResponseDTOS)) {
  38. log.info("============未查询到任何分类==============");
  39. return JsonResponse.ok(Collections.EMPTY_LIST);
  40. }
  41. log.info("============一级分类查询result:{}==============", categoryResponseDTOS);
  42. return JsonResponse.ok(categoryResponseDTOS);
  43. }
  44. }
Test API

编写完成之后,我们需要对我们的代码进行测试验证,还是通过使用RestService插件来实现,当然,大家也可以通过Postman来测试。

  1. {
  2. "status": 200,
  3. "message": "OK",
  4. "data": [
  5. {
  6. "id": 1,
  7. "name": "烟酒",
  8. "type": 1,
  9. "parentId": 0,
  10. "logo": "img/cake.png",
  11. "slogan": "吸烟受害健康",
  12. "catImage": "http://www.life-runner.com/shop/category/cake.png",
  13. "bgColor": "#fe7a65"
  14. },
  15. {
  16. "id": 2,
  17. "name": "服装",
  18. "type": 1,
  19. "parentId": 0,
  20. "logo": "img/cookies.png",
  21. "slogan": "我选择我喜欢",
  22. "catImage": "http://www.life-runner.com/shop/category/cookies.png",
  23. "bgColor": "#f59cec"
  24. },
  25. {
  26. "id": 3,
  27. "name": "鞋帽",
  28. "type": 1,
  29. "parentId": 0,
  30. "logo": "img/meat.png",
  31. "slogan": "飞一般的感觉",
  32. "catImage": "http://www.life-runner.com/shop/category/meat.png",
  33. "bgColor": "#b474fe"
  34. }
  35. ],
  36. "ok": true
  37. }

根据一级分类查询子分类

因为根据一级id查询子分类的时候,我们是在同一张表中做自连接查询,因此,通用mapper已经不适合我们的使用,因此我们需要自定义mapper来实现我们的需求。

自定义Mybatis Mapper实现

在之前的编码中,我们都是使用的插件帮我们实现的通用Mapper,但是这种查询只能处理简单的单表CRUD,一旦我们需要SQL 包含一部分逻辑处理的时候,那就必须得自己来编写了,let's code.

1.在项目mscx-shop-mapper中,创建一个新的custom package,在该目录下创建自定义mappercom.liferunner.custom.CategoryCustomMapper

  1. public interface CategoryCustomMapper {
  2. List<SecondSubCategoryResponseDTO> getSubCategorys(Integer parentId);
  3. }

2.resources目录下创建目录mapper.custom,以及创建和上面的接口相同名称的XML文件mapper/custom/CategoryCustomMapper.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="com.liferunner.custom.CategoryCustomMapper">
  4. <resultMap id="subCategoryDTO" type="com.liferunner.dto.SecondSubCategoryResponseDTO">
  5. <id column="id" jdbcType="INTEGER" property="id"/>
  6. <result column="name" jdbcType="VARCHAR" property="name"/>
  7. <result column="type" jdbcType="INTEGER" property="type"/>
  8. <result column="parentId" jdbcType="INTEGER" property="parentId"/>
  9. <collection property="thirdSubCategoryResponseDTOList" ofType="com.liferunner.dto.ThirdSubCategoryResponseDTO">
  10. <id column="subId" jdbcType="INTEGER" property="subId"/>
  11. <result column="subName" jdbcType="VARCHAR" property="subName"/>
  12. <result column="subType" jdbcType="INTEGER" property="subType"/>
  13. <result column="subParentId" jdbcType="INTEGER" property="subParentId"/>
  14. </collection>
  15. </resultMap>
  16. <select id="getSubCategorys" resultMap="subCategoryDTO" parameterType="INTEGER">
  17. SELECT p.id as id,p.`name` as `name`,p.`type` as `type`,p.father_id as parentId,
  18. c.id as subId,c.`name` as subName,c.`type` as subType,c.parent_id as subParentId
  19. FROM category p
  20. LEFT JOIN category c
  21. ON p.id = c.parent_id
  22. WHERE p.parent_id = ${parentId};
  23. </select>
  24. </mapper>

TIPS

上述创建的package,一定要在项目的启动类com.liferunner.api.ApiApplication中修改@MapperScan(basePackages = { "com.liferunner.mapper", "com.liferunner.custom"}),如果不把我们的custom package加上,会造成扫描不到而报错。

在上面的xml中,我们定义了两个DTO对象,分别用来处理二级和三级分类的DTO,实现如下:

  1. @Data
  2. @ToString
  3. public class SecondSubCategoryResponseDTO {
  4. /**
  5. * 主键
  6. */
  7. private Integer id;
  8. /**
  9. * 分类名称
  10. */
  11. private String name;
  12. /**
  13. * 分类类型
  14. 1:一级大分类
  15. 2:二级分类
  16. 3:三级小分类
  17. */
  18. private Integer type;
  19. /**
  20. * 父id
  21. */
  22. private Integer parentId;
  23. List<ThirdSubCategoryResponseDTO> thirdSubCategoryResponseDTOList;
  24. }
  25. ---
  26. @Data
  27. @ToString
  28. public class ThirdSubCategoryResponseDTO {
  29. /**
  30. * 主键
  31. */
  32. private Integer subId;
  33. /**
  34. * 分类名称
  35. */
  36. private String subName;
  37. /**
  38. * 分类类型
  39. 1:一级大分类
  40. 2:二级分类
  41. 3:三级小分类
  42. */
  43. private Integer subType;
  44. /**
  45. * 父id
  46. */
  47. private Integer subParentId;
  48. }
Service实现

编写完自定义mapper之后,我们就可以继续编写service了,在com.liferunner.service.ICategoryService中新增一个方法:getAllSubCategorys(parentId).如下:

  1. public interface ICategoryService {
  2. ...
  3. /**
  4. * 根据一级分类获取子分类
  5. *
  6. * @param parentId 一级分类id
  7. * @return 子分类list
  8. */
  9. List<SecondSubCategoryResponseDTO> getAllSubCategorys(Integer parentId);
  10. }

com.liferunner.service.impl.CategorySericeImpl实现上述方法:

  1. @Service
  2. @Slf4j
  3. public class CategorySericeImpl implements ICategoryService {
  4. @Autowired
  5. private CategoryMapper categoryMapper;
  6. @Autowired
  7. private CategoryCustomMapper categoryCustomMapper;
  8. ...
  9. @Override
  10. @Transactional(propagation = Propagation.SUPPORTS)
  11. public List<SecondSubCategoryResponseDTO> getAllSubCategorys(Integer parentId) {
  12. return this.categoryCustomMapper.getSubCategorys(parentId);
  13. }
  14. }
Controller实现
  1. @RestController
  2. @RequestMapping("/index")
  3. @Api(value = "首页信息controller", tags = "首页信息接口API")
  4. @Slf4j
  5. public class IndexController {
  6. @Autowired
  7. private ICategoryService categoryService;
  8. ...
  9. @GetMapping("/subCategorys/{parentId}")
  10. @ApiOperation(value = "查询子分类", notes = "根据一级分类id查询子分类")
  11. public JsonResponse findAllSubCategorys(
  12. @ApiParam(name = "parentId", value = "一级分类id", required = true)
  13. @PathVariable Integer parentId) {
  14. log.info("============查询id = {}的子分类==============", parentId);
  15. val categoryResponseDTOS = this.categoryService.getAllSubCategorys(parentId);
  16. if (CollectionUtils.isEmpty(categoryResponseDTOS)) {
  17. log.info("============未查询到任何分类==============");
  18. return JsonResponse.ok(Collections.EMPTY_LIST);
  19. }
  20. log.info("============子分类查询result:{}==============", categoryResponseDTOS);
  21. return JsonResponse.ok(categoryResponseDTOS);
  22. }
  23. }
Test API
  1. {
  2. "status": 200,
  3. "message": "OK",
  4. "data": [
  5. {
  6. "id": 11,
  7. "name": "国产",
  8. "type": 2,
  9. "parentId": 1,
  10. "thirdSubCategoryResponseDTOList": [
  11. {
  12. "subId": 37,
  13. "subName": "中华",
  14. "subType": 3,
  15. "subParentId": 11
  16. },
  17. {
  18. "subId": 38,
  19. "subName": "冬虫夏草",
  20. "subType": 3,
  21. "subParentId": 11
  22. },
  23. {
  24. "subId": 39,
  25. "subName": "南京",
  26. "subType": 3,
  27. "subParentId": 11
  28. },
  29. {
  30. "subId": 40,
  31. "subName": "云烟",
  32. "subType": 3,
  33. "subParentId": 11
  34. }
  35. ]
  36. },
  37. {
  38. "id": 12,
  39. "name": "外烟",
  40. "type": 2,
  41. "parentId": 1,
  42. "thirdSubCategoryResponseDTOList": [
  43. {
  44. "subId": 44,
  45. "subName": "XXXXX",
  46. "subType": 3,
  47. "subParentId": 12
  48. },
  49. {
  50. "subId": 45,
  51. "subName": "RRRRR",
  52. "subType": 3,
  53. "subParentId": 12
  54. }
  55. ]
  56. }
  57. ],
  58. "ok": true
  59. }

以上我们就已经实现了和jd类似的商品分类的功能实现。

轮播广告|SlideAD

需求分析

这个就是jd或者tb首先的最顶部的广告图片是一样的,每隔1秒自动切换图片。接下来我们分析一下轮播图中都包含哪些信息:

  • 图片(img_url)是最基本的
  • 图片跳转连接(img_link_url),这个是在我们点击这个图片的时候需要跳转到的页面
  • 有的可以直接跳转到商品详情页面
  • 有的可以直接跳转到某一分类商品列表页面
  • 轮播图的播放顺序(sort)
  • ...

开发梳理

直接查询出所有的有效的轮播图片,并且进行排序

编码实现

Service 实现

和商品分类实现一样,在mscx-shop-service中创建com.liferunner.service.ISlideAdService并实现,代码如下:

  1. public interface ISlideAdService {
  2. /**
  3. * 查询所有可用广告并排序
  4. * @param isShow
  5. * @return
  6. */
  7. List<SlideAdResponseDTO> findAll(Integer isShow, String sortRanking);
  8. }
  1. @Service
  2. @Slf4j
  3. public class SlideAdServiceImpl implements ISlideAdService {
  4. // 注入mapper
  5. private final SlideAdsMapper slideAdsMapper;
  6. @Autowired
  7. public SlideAdServiceImpl(SlideAdsMapper slideAdsMapper) {
  8. this.slideAdsMapper = slideAdsMapper;
  9. }
  10. @Override
  11. public List<SlideAdResponseDTO> findAll(Integer isShow, String sortRanking) {
  12. Example example = new Example(SlideAds.class);
  13. //设置排序
  14. if (StringUtils.isBlank(sortRanking)) {
  15. example.orderBy("sort").asc();
  16. } else {
  17. example.orderBy("sort").desc();
  18. }
  19. val conditions = example.createCriteria();
  20. conditions.andEqualTo("isShow", isShow);
  21. val slideAdsList = this.slideAdsMapper.selectByExample(example);
  22. //声明返回对象
  23. List<SlideAdResponseDTO> slideAdResponseDTOList = new ArrayList<>();
  24. if (!CollectionUtils.isEmpty(slideAdsList)) {
  25. //赋值
  26. SlideAdResponseDTO dto;
  27. for (SlideAds slideAds : slideAdsList) {
  28. dto = new SlideAdResponseDTO();
  29. BeanUtils.copyProperties(slideAds, dto);
  30. slideAdResponseDTOList.add(dto);
  31. }
  32. }
  33. return slideAdResponseDTOList;
  34. }
  35. }

从上述可以看到,这里我使用的是构造函数注入SlideAdsMapper,其余代码单表查询没什么特别的,根据条件查询轮播图,并返回结果,返回的对象是com.liferunner.dto.SlideAdResponseDTO列表,代码如下:

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. @Builder
  5. @ApiModel(value = "轮播广告返回DTO", description = "轮播广告返回DTO")
  6. public class SlideAdResponseDTO{
  7. /**
  8. * 主键
  9. */
  10. private String id;
  11. /**
  12. * 图片地址
  13. */
  14. private String imageUrl;
  15. /**
  16. * 背景颜色
  17. */
  18. private String backgroundColor;
  19. /**
  20. * 商品id
  21. */
  22. private String productId;
  23. /**
  24. * 商品分类id
  25. */
  26. private String catId;
  27. /**
  28. * 图片跳转URL
  29. */
  30. private String imageLinkUrl;
  31. /**
  32. * 轮播图类型 用于判断,可以根据商品id或者分类进行页面跳转,1:商品 2:分类 3:链接url
  33. */
  34. private Integer type;
  35. /**
  36. * 轮播图展示顺序 轮播图展示顺序,从小到大
  37. */
  38. private Integer sort;
  39. /**
  40. * 是否展示 是否展示,1:展示 0:不展示
  41. */
  42. private Integer isShow;
  43. /**
  44. * 创建时间 创建时间
  45. */
  46. private Date createTime;
  47. /**
  48. * 更新时间 更新
  49. */
  50. private Date updateTime;
  51. }

Controller实现

com.liferunner.api.controller.IndexController中,新添加一个查询轮播图API,代码如下:

  1. @Autowired
  2. private ISlideAdService slideAdService;
  3. @GetMapping("/slideAds")
  4. @ApiOperation(value = "查询轮播广告", notes = "查询轮播广告接口")
  5. public JsonResponse findAllSlideList() {
  6. log.info("============查询所有轮播广告,isShow={},sortRanking={}=============="
  7. , 1, "desc");
  8. val slideAdsList = this.slideAdService.findAll(1, "desc");
  9. if (CollectionUtils.isEmpty(slideAdsList)) {
  10. log.info("============未查询到任何轮播广告==============");
  11. return JsonResponse.ok(Collections.EMPTY_LIST);
  12. }
  13. log.info("============轮播广告查询result:{}=============="
  14. , slideAdsList);
  15. return JsonResponse.ok(slideAdsList);
  16. }

Test API

  1. {
  2. "status": 200,
  3. "message": "OK",
  4. "data": [
  5. {
  6. "id": "slide-100002",
  7. "imageUrl": "http://www.life-runner.com/2019/11/CpoxxF0ZmH6AeuRrAAEZviPhyQ0768.png",
  8. "backgroundColor": "#55be59",
  9. "productId": "",
  10. "catId": "133",
  11. "type": 2,
  12. "sort": 2,
  13. "isShow": 1,
  14. "createTime": "2019-10-11T21:33:01.000+0000",
  15. "updateTime": "2019-10-11T21:33:02.000+0000"
  16. },
  17. {
  18. "id": "slide-100003",
  19. "imageUrl": "http://www.life-runner.com/2019/11/CpoxxF0ZmHuAPlXvAAFe-H5_-Nw961.png",
  20. "backgroundColor": "#ff9801",
  21. "productId": "y200008",
  22. "catId": "",
  23. "type": 1,
  24. "sort": 1,
  25. "isShow": 1,
  26. "createTime": "2019-10-11T21:33:01.000+0000",
  27. "updateTime": "2019-10-11T21:33:02.000+0000"
  28. }
  29. ],
  30. "ok": true
  31. }

福利讲解

在我们的实现代码中,有心的同学可以看到,我使用了3种不同的Bean注入方式:

  • 属性注入
  1. @Autowired
  2. private ISlideAdService slideAdService;
  • 构造函数注入
  1. // 注入mapper
  2. private final SlideAdsMapper slideAdsMapper;
  3. @Autowired
  4. public SlideAdServiceImpl(SlideAdsMapper slideAdsMapper) {
  5. this.slideAdsMapper = slideAdsMapper;
  6. }
  • Lombok插件注入(本质也是构造器注入,代码会动态生成。)
  1. @RequiredArgsConstructor(onConstructor = @__(@Autowired))
  2. public class ProductServiceImpl implements IProductService {
  3. // RequiredArgsConstructor 构造器注入
  4. private final ProductCustomMapper productCustomMapper;
  5. private final ProductsMapper productsMapper;
  6. ...
  7. }

那么,这几种注入都有什么区别呢?首先我们下了解一下Spring的注入是干什么的?

Spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过Spring容器帮我们new指定实例并且将实例注入到需要该对象的类中。

依赖注入的另一种说法是"控制反转"。通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员, 而控制反转是指new实例工作不由我们程序员来做而是交给Spring容器来做。

在传统的SpringMVC中,大家使用的都是XML注入,比如:

  1. <!--配置bean,配置后该类由spring管理-->
  2. <bean name="CategorySericeImpl" class="com.liferunner.service.impl.CategorySericeImpl">
  3. <!--注入配置当前类中相应的属性-->
  4. <property name="categoryMapper" ref="categoryMapper"></property>
  5. </bean>
  6. <bean name="categoryMapper" class="com.liferunner.mapper.CategoryMapper"></bean>

注入之后,使用@Autowired,我们可以很方便的自动从IOC容器中查找属性,并返回。

@Autowired的原理

在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。

注意事项:

在使用@Autowired时,首先在容器中查询对应类型的bean

如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据

如果查询的结果不止一个,那么@Autowired会根据名称来查找。

如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false

source传送门

上述三种注解方式,其实本质上还是注入的2种:set属性注入 & 构造器注入,使用方式都可以,根据个人喜好来用,本人喜欢使用lombok插件注入是因为,它将代码整合在一起,更加符合我们Spring自动注入的规范。

源码下载

Github 传送门

Gitee 传送门

下节预告

下一节我们将继续开发我们电商的核心部分-商品列表和详情展示,在过程中使用到的任何开发组件,我都会通过专门的一节来进行介绍的,兄弟们末慌!

gogogo!

[springboot 开发单体web shop] 6. 商品分类和轮播广告展示的更多相关文章

  1. 开发单体web shop] 6. 商品分类和轮播广告展示

    目录 商品分类&轮播广告 商品分类|ProductCategory 需求分析 开发梳理 编码实现 轮播广告|SlideAD 需求分析 开发梳理 编码实现 福利讲解 源码下载 下节预告 商品分类 ...

  2. [springboot 开发单体web shop] 7. 多种形式提供商品列表

    上文回顾 上节 我们实现了仿jd的轮播广告以及商品分类的功能,并且讲解了不同的注入方式,本节我们将继续实现我们的电商主业务,商品信息的展示. 需求分析 首先,在我们开始本节编码之前,我们先来分析一下都 ...

  3. [springboot 开发单体web shop] 1. 前言介绍和环境搭建

    前言介绍和环境搭建 简述 springboot 本身是为了做服务化用的,我们为什么要反其道使用它来开发一份单体web应用呢? 在我们现实的开发工作中,还有大量的业务系统使用的是单体应用,特别是对于中小 ...

  4. [springboot 开发单体web shop] 4. Swagger生成Javadoc

    Swagger生成JavaDoc 在日常的工作中,特别是现在前后端分离模式之下,接口的提供造成了我们前后端开发人员的沟通 成本大量提升,因为沟通不到位,不及时而造成的[撕币]事件都成了日常工作.特别是 ...

  5. [springboot 开发单体web shop] 5. 用户登录及首页展示

    用户登录及前端展示 用户登录 在之前的文章中我们实现了用户注册和验证功能,接下来我们继续实现它的登录,以及登录成功之后要在页面上显示的信息. 接下来,我们来编写代码. 实现service 在com.l ...

  6. [springboot 开发单体web shop] 2. Mybatis Generator 生成common mapper

    Mybatis Generator tool 在我们开启一个新项目的研发后,通常要编写很多的entity/pojo/dto/mapper/dao..., 大多研发兄弟们都会抱怨,为什么我要重复写CRU ...

  7. [springboot 开发单体web shop] 8. 商品详情&评价展示

    上文回顾 上节 我们实现了根据搜索关键词查询商品列表和根据商品分类查询,并且使用到了mybatis-pagehelper插件,讲解了如何使用插件来帮助我们快速实现分页数据查询.本文我们将继续开发商品详 ...

  8. [springboot 开发单体web shop] 3. 用户注册实现

    目录 用户注册 ## 创建数据库 ## 生成UserMapper ## 编写业务逻辑 ## 编写user service UserServiceImpl#findUserByUserName 说明 U ...

  9. Android开发工程师文集-Fragment,适配器,轮播图,ScrollView,Gallery 图片浏览器,Android常用布局样式

    Android开发工程师文集-Fragment,适配器,轮播图,ScrollView,Gallery 图片浏览器,Android常用布局样式 Fragment FragmentManager frag ...

随机推荐

  1. Python3字符串常见方法

    目录 字符串的进阶使用 格式化输出字符串 当然除了上述方法外,还可以你使用format方法 format方法第二种用法: Python字符串与二进制的转换 字母大写 计字符a出现的次数 输出50个字符 ...

  2. [NOIp2011] luogu P1313 计算系数

    继续水博客,待会回去上术学. 题目描述 给定一个多项式 (by+ax)k(by+ax)^k(by+ax)k ,请求出多项式展开后 xn×ymx^n \times y^mxn×ym 项的系数. Solu ...

  3. [NOIp2018] luogu P5021 赛道修建

    我同学的歌 题目描述 你有一棵树,每条边都有权值 did_idi​.现在要修建 mmm 条赛道,一条赛道是一条连贯的链,且一条边至多出现在一条赛道里.一条赛道的长被定义为,组成这条赛道的边的权值之和. ...

  4. C# 控件 RichTextBox 显示行号,并且与Panel相互联动

    我们在使用到WINFORM窗体工作中,要求RichTextBox 加入行号: 之前有看到大牛们写的,但是太复杂繁多,而且有用双TextBox进行联动,非常不错,今天我们尝试RichTextBox +P ...

  5. 上传文件夹或上传文件到linux

    http://jingyan.baidu.com/article/d169e18658995a436611d8ee.html https://www.cnblogs.com/nbf-156cwl/p/ ...

  6. unittest-A接口的返回结果作为B接口的入参(设置全局变量)

    在A接口用例中设置全局变量: globals()["a"] = "用例A的返回结果" 在B接口用例中使用全局变量: b = globals()["a& ...

  7. JavaScript中valueOf、toString的隐式调用

    今天在群上有人问这样一个问题: 函数add可以实现连续的加法运算函数add语法如下add(num1)(num2)(num3)...;//注意这里是省略号哟,无限使用举例如下:add(10)(10)=2 ...

  8. 百万年薪python之路 -- 并发编程之 多线程 一

    多线程 1.进程: 生产者消费者模型 一种编程思想,模型,设计模式,理论等等,都是交给你一种编程的方法,以后遇到类似的情况,套用即可 生产者与消费者模型的三要素: 生产者:产生数据的 消费者:接收数据 ...

  9. day1-02 python程序语法分析

    一.概述 程序的格式框架 命名与保留字 数据类型 语句与函数 Python程序的输入输出 二.程序的格式框架 # TempConvert.py # 输入温度 TempStr = input(" ...

  10. Golang的安装和编译

    一.下载安装(Ubuntu16.04) 1.下载地址:https://golang.google.cn/dl/ 2.下载Linux版本的安装包go1.10.3.linux-amd64.tar.gz并复 ...