尚好房是一个二手房管理服务平台,开放优质资源和线上能力,聚合线上线下二手房产资源,打造一个全方位二手房服务生态市场,为消费者提供优质房产服务资源。
根据演示了解项目业务
尚好房后台管理系统:权限管理系统
尚好房前端:找房网

BaseController,里面真的很简单,但是考虑到以后每一个Controller都要用到封装的那俩行代码,
在新增,修改添加成功会用得到。是用来给消费者的Controller继承的。
- public class BaseController {
- private final static String PAGE_SUCCESS = "common/successPage";
- public String successPage(Model model, String successMessage){
- model.addAttribute("messagePage",successMessage);
- return PAGE_SUCCESS;
- }
- }
BaseService是用来给中间商“service-api”来继承的,

它里面的内容是下面这样子的,继承了它就相当于Service里写了五个通用的增删改查方法
- public interface BaseService<T> {
- void insert(T t);
-
- T getById(Long id);
-
- /**
- * 逻辑删除
- * @param id
- */
- void delete(Long id);
-
- /**
- * 修改信息
- * @param t
- */
- void update(T t);
-
- /**
- * 分页查询信息
- * @param filters
- * @return
- */
- PageInfo<T> findPage(Map<String, Object> filters);
- }
BaseServiceImpl和BaseMapper就是让服务的提供者去使用继承的。一个写具体的业务逻辑,一个写对数据库的操作。
这里BaseServiceImpl是一个抽象类,它里面有一个抽象方法getEntityMapper(),这个方法就是为了让继承它的子类去重写它,把正真的mapper接口送给他,他好帮你去调用方法呐
- public abstract class BaseServiceImpl<T> {
-
- /**
- * 该抽象方法用来获取真实的mapper接口
- * @return
- */
- protected abstract BaseMapper<T> getEntityMapper();
-
- public void insert(T t) {
- getEntityMapper().insert(t);
- }
-
- @Transactional(propagation = Propagation.SUPPORTS)
- public T getById(Long id) {
- return getEntityMapper().getById(id);
- }
-
-
- public void delete(Long id) {
- getEntityMapper().delete(id);
- }
-
-
- public void update(T t) {
- getEntityMapper().update(t);
- }
-
- @Transactional(propagation = Propagation.SUPPORTS)
- public PageInfo<T> findPage(Map<String, Object> filters) {
- //将pageSize和pageNum强转成int类型
- //第二个参数表示如果强转失败给默认值
- int pageNum = CastUtil.castInt(filters.get("pageNum"),1);
- int pageSize = CastUtil.castInt(filters.get("pageSize"),10);
- //开启分页
- PageHelper.startPage(pageNum,pageSize);
- //调用持久层的方法查询数据集
- //封装返回结果,老师这里没有传第二个参数
- return new PageInfo<>(getEntityMapper().findPage(filters),10);
- }
- }
最后就是这BaseMapper了,我们创建的每一个mapper接口都要去继承这个接口,这样我们的mapper接口就可以省略掉这五个最常用的方法不写了
- public interface BaseMapper<T> {
-
- /**
- * 保存一个实体
- * @param t
- */
- void insert(T t);
-
- /**
- * 通过一个标识ID 获取一个唯一实体
- * @param id
- * @return
- */
- T getById(Long id);
-
- /**
- *修改
- * @param t
- */
- void update(T t);
-
- /**
- * 删除
- * @param id
- */
- void delete(Long id);
-
- /**
- * 分页查询
- * @param filters
- * @return
- */
- Page<T> findPage(Map<String, Object> filters);
- }
这个字典表本身就设计的巧妙

这个页面的视觉效果也很nice:这种树形的目录看着很高级,实际上后端返给前端的也只是一个json数组。

java后端代码:
后端逻辑就很简单,根据父节点的id去查询所有的子节点,把查出来的数据用Stream流做整理。
2021/11/12 北京 stream流,内部类,lambda表达式_£小羽毛的博客-CSDN博客
- public List<Map<String, Object>> findZnodes(Long id) {
- //1. 调用持久层方法,根据父节点id查询List<Dict>
- List<Dict> dictList = dictMapper.findListByParentId(id);
- //使用Stream流
- List<Map<String, Object>> znodes = dictList.stream()
- .map(dict -> {
- Map<String, Object> znode = new HashMap<>();
- //往znode中存放id
- znode.put("id", dict.getId());
- //往znode中存放name
- znode.put("name", dict.getName());
- //往znode中存放isParent
- znode.put("isParent", dictMapper.countIsParent(dict.getId()) > 0);
- return znode;
- })
- .collect(Collectors.toList());
- return znodes;
- }
在SQlyog中执行如下sql:
- -- 根据父节点的id去查询所有的子节点
- SELECT * FROM hse_dict WHERE parent_id =1

点击全部分类

观察network,发送了这样一个请求,那不就是咱上面分析的那种情况嘛
http://139.198.152.148:8001/dict/findZnodes?id=1
返给前端的json数据:实际上返回的还是json数组。
- {
- "code": 200,
- "data": [
- {
- "isParent": true,
- "name": "户型",
- "id": 10000
- },
- {
- "isParent": true,
- "name": "楼层",
- "id": 20000
- },
- {
- "isParent": true,
- "name": "建筑结构",
- "id": 30000
- },
- {
- "isParent": true,
- "name": "装修情况",
- "id": 40000
- },
- {
- "isParent": true,
- "name": "朝向",
- "id": 50000
- },
- {
- "isParent": true,
- "name": "房屋用途",
- "id": 60000
- },
- {
- "isParent": true,
- "name": "省",
- "id": 100000
- }
- ],
- "message": "成功",
- "ok": true
- }
我们再点击户型,此时再发送请求去查询
http://139.198.152.148:8001/dict/findZnodes?id=10000

返给前端的json数组如下:
- {
- "code": 200,
- "data": [
- {
- "isParent": false,
- "name": "一室",
- "id": 10001
- },
- {
- "isParent": false,
- "name": "两室",
- "id": 10002
- },
- {
- "isParent": false,
- "name": "三室",
- "id": 10003
- },
- {
- "isParent": false,
- "name": "四室",
- "id": 10004
- },
- {
- "isParent": false,
- "name": "四室以上",
- "id": 10005
- }
- ],
- "message": "成功",
- "ok": true
- }
用法1:房源的发布状态HouseStatus
- public enum HouseStatus {
- //未发布表示用户看不到,但是后台管理系统可以看得到
- PUBLISHED(1,"已发布"), UNPUBLISHED(0,"未发布");
- public int code;
- public String message;
-
- HouseStatus(int code, String message) {
- this.code = code;
- this.message = message;
- }
- }
在添加房源信息的时候使用:
- @PostMapping("/save")
- public String save(House house,Model model){
- //未发布
- house.setStatus(HouseStatus.UNPUBLISHED.code);
- houseService.insert(house);
- return successPage(model,"添加房源信息成功");
- }
枚举用法2:定义为私有变量。
- public enum DictCode {
- HOUSETYPE("houseType"),FLOOR("floor"),BUILDSTRUCTURE("buildStructure"),
- DECORATION("decoration"),DIRECTION("direction"),HOUSEUSE("houseUse");
- private String message;
-
- DictCode(String message) {
- this.message = message;
- }
- public String getMessage() {
- return message;
- }
- }
使用:
- //3. 查询各种初始化列表:户型列表、楼层列表、装修情况列表....
- List<Dict> houseTypeList =
- dictService.findDictListByParentDictCode(DictCode.HOUSETYPE.getMessage());
getListingDateString() House类
在thymeleaf语法中,在请求域中是用get方法拿到值的