您的位置:首页 > 娱乐 > 八卦 > web前端开发培训学校_短链接_推广方案的内容有哪些_线上推广平台报价

web前端开发培训学校_短链接_推广方案的内容有哪些_线上推广平台报价

2024/12/22 15:02:34 来源:https://blog.csdn.net/m0_45253972/article/details/144514084  浏览:    关键词:web前端开发培训学校_短链接_推广方案的内容有哪些_线上推广平台报价
web前端开发培训学校_短链接_推广方案的内容有哪些_线上推广平台报价

代码生成

在使用MybatisPlus以后,基础的MapperServicePO代码相对固定,重复编写也比较麻烦。因此MybatisPlus官方提供了代码生成器根据数据库表结构生成POMapperService等相关代码。只不过代码生成器同样要编码使用,也很麻烦。

这里推荐大家使用一款MybatisPlus的插件,它可以基于图形化界面完成MybatisPlus的代码生成,非常简单。

安装插件

Idea的plugins市场中搜索并安装MyBatisPlus插件:

在这里插入图片描述

然后重启你的Idea即可使用。

使用

刚好数据库中还有一张address表尚未生成对应的实体和mapper等基础代码。我们利用插件生成一下。 首先需要配置数据库地址,在Idea顶部菜单中,找到Tools,选择Config Database

在这里插入图片描述

在弹出的窗口中填写数据库连接的基本信息:

在这里插入图片描述

点击OK保存。

然后再次点击Idea顶部菜单中的other,然后选择Code Generator:

在这里插入图片描述

在弹出的表单中填写信息:

在这里插入图片描述

最终,代码自动生成到指定的位置了:

静态工具

有的时候Service之间也会相互调用,比如某些业务在UserService中实现,查adderss信息需要注入AddressService。有些业务在AddressService中实现,查询user信息需要注入UserService,两个Service相互注入就会出现循环依赖的情况。为了避免出现循环依赖问题,MybatisPlus提供一个静态工具类Db,其中的一些静态方法与IService中方法签名基本一致,也可以帮助我们实现CRUD功能。与IService接口的主要区别是,删除和查询除了传id集合还需要传Class掩码指定对象类型完成反射。只有save和update不需要传,因为save和update直接传送对象,对象都有了不需要字节码了:

在这里插入图片描述

示例:

@Test
void testDbGet() {User user = Db.getById(1L, User.class);System.out.println(user);
}@Test
void testDbList() {// 利用Db实现复杂条件查询List<User> list = Db.lambdaQuery(User.class).like(User::getUsername, "o").ge(User::getBalance, 1000).list();list.forEach(System.out::println);
}@Test
void testDbUpdate() {Db.lambdaUpdate(User.class).set(User::getBalance, 2000).eq(User::getUsername, "Rose");
}

需求:

改造根据id用户查询的接口,查询用户的同时返回用户收货地址列表。

首先,我们要添加一个收货地址的VO对象:

package com.itheima.mp.domain.vo;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
@ApiModel(description = "收货地址VO")
public class AddressVO{@ApiModelProperty("id")private Long id;@ApiModelProperty("用户ID")private Long userId;@ApiModelProperty("省")private String province;@ApiModelProperty("市")private String city;@ApiModelProperty("县/区")private String town;@ApiModelProperty("手机")private String mobile;@ApiModelProperty("详细地址")private String street;@ApiModelProperty("联系人")private String contact;@ApiModelProperty("是否是默认 1默认 0否")private Boolean isDefault;@ApiModelProperty("备注")private String notes;
}

然后,改造原来的UserVO,添加一个地址属性:

在这里插入图片描述

接下来,修改UserController中根据id查询用户的业务接口:

@GetMapping("/{id}")
@ApiOperation("根据id查询用户")
public UserVO queryUserById(@PathVariable("id") Long userId){// 基于自定义service方法查询return userService.queryUserAndAddressById(userId);
}

由于查询业务复杂,所以要在service层来实现。首先在IUserService中定义方法:

package com.itheima.mp.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.vo.UserVO;public interface IUserService extends IService<User> {void deduct(Long id, Integer money);UserVO queryUserAndAddressById(Long userId);
}

然后,在UserServiceImpl中实现该方法:

@Override
public UserVO queryUserAndAddressById(Long userId) {// 1.查询用户User user = getById(userId);if (user == null || user.getStatus() == 2) {throw new RuntimeException("用户状态异常!");}// 2.查询收货地址List<Address> addresses = Db.lambdaQuery(Address.class).eq(Address::getUserId, userId).list();// 3.处理vo// 转user的PO为VOUserVO userVO = BeanUtil.copyProperties(user, UserVO.class);// 转地址的VOif(Collutil.isNotEmpty(addresses)){userVO.setAddresses(BeanUtil.copyToList(addresses, AddressVO.class));}return userVO;
}

在查询地址时,我们采用了Db的静态方法,因此避免了注入AddressService,减少了循环依赖的风险。
在这里插入图片描述

再来实现一个功能:

根据id批量查询用户,并查询出用户对应的所有地址。

UserController:

    @ApiOperation("根据id批量查询用户")@GetMappingpublic List<UserVo> queryUserById(@ApiParam("用户id集合") @RequestParam("ids") List<Long> ids){// 根据service方法实现查询return userService.queryUserAndAddressByIds(ids);}

IUserService:

List<UserVo> queryUserAndAddressByIds(List<Long> ids);

UserServiceImpl:

    @Overridepublic List<UserVo> queryUserAndAddressByIds(List<Long> ids) {// 1.批量查询用户信息List<User> users = listByIds(ids);if(users.isEmpty(users)){return null;}// 2.根据id查询用户的收货地址信息List<UserVo> userVos = users.stream().map(user -> {// 将user拷贝到voUserVo userVO = BeanUtil.copyProperties(user, UserVo.class);List<Address> addressList = Db.lambdaQuery(Address.class).eq(Address::getUserId, user.getId()).list();userVO.setAddress(BeanUtil.copyToList(addressList, AddressVO.class));return userVO;}).collect(Collectors.toList());return userVos;}

在循环里面查询的效率很低,可以批量分开查询。

 @Overridepublic List<UserVo> queryUserAndAddressByIds(List<Long> ids) {// 1.批量查询用户信息List<User> users = listByIds(ids);if(users.isEmpty(users)){return Collections.emptyList();}// 2.查询地址// 2.1 获取用户id集合List<Long> ids = users.stream().map(User::getId).collect(Collectors.toList());// 2.2 根据用户id查询地址List<Address> address = Db.lambdaQuery(Adress.class).in(Address::getUserId, userIds).list();// 2.3 转换地址VOList<AdressVO> addressVOList = BeanUtil.copyTolist(addresss,AddressVO.class);// 2.4用户地址集合分组处理,相同用户的放入一个集合(组)中// 创建一个空的Map集合Map<Long,List<AddressVO>> addressMap = new HashMap<>(0);// 如果地址VO集合不为空,需要根据id分组转换到Map集合中。if(CollUtil.isNotEmpty(addressVOList)){// 地址Map中,用户id为键,对应的地址集合为值。addressMap = addressVOList.stream().collect(Collectors.groupingBy(AdressVO::getUserId));}// 3.转换VO返回List<UserVO> list = new ArrayList<>(users,size());for(User user : users){// 3.1 转换User的PO为VOUserVO vo = BeanUtil.copyProperties(user, UserVO.class);list.add(vo);// 3.2 转换地址VOvo.setAddresses(addressMap.get(user.getId());}return userVos;}

在这里插入图片描述

逻辑删除

对于一些比较重要的数据,我们往往会采用逻辑删除的方案,即:

  • 在表中添加一个字段标记数据是否被删除
  • 当删除数据时把标记置为true
  • 查询时过滤掉标记为true的数据

逻辑删除字段的为deleted:

  • 删除操作为 UPDATE user SET deleted = 1 WHERE id = 1 AND deleted = 0
  • 查询操作: SELECT * FROM user WHERE deleted = 0

一旦采用了逻辑删除,所有的查询和删除逻辑都要跟着变化,非常麻烦。

为了解决这个问题,MybatisPlus就添加了对逻辑删除的支持。

注意,只有MybatisPlus生成的SQL语句才支持自动的逻辑删除,自定义SQL需要自己手动处理逻辑删除。

添加逻辑删除字段

例如,我们给address表添加一个逻辑删除字段:

alter table address add deleted bit default b'0' null comment '逻辑删除';

然后给Address实体添加deleted字段:

在这里插入图片描述

配置逻辑删除字段

接下来,我们要在application.yml中配置逻辑删除字段:

mybatis-plus:type-aliases-package: com.itheima.mp.domain.poglobal-config:db-config:id-type: autologic-delete-field: deleted #配置逻辑删除字段

测试

创建IAddressService接口的测试类,并执行一个删除操作:

@SpringBootTest
class IAddressServiceTest {@Autowiredprivate IAddressService addressService;//    逻辑删除@Testpublic void testLogicDelete() {// 1.执行逻辑删除操作addressService.removeById(60L);// 2. 执行查询操作addressService.getById(60L);}
}

方法与普通删除一模一样,但是底层的SQL逻辑变了:

在这里插入图片描述

在这里插入图片描述

综上, 开启了逻辑删除功能以后,我们就可以像普通删除一样做CRUD,基本不用考虑代码逻辑问题。还是非常方便的。

注意: 逻辑删除本身也有自己的问题,比如:

  • 会导致数据库表垃圾数据越来越多,从而影响查询效率
  • SQL中全都需要对逻辑删除字段做判断,影响查询效率

因此,我不太推荐采用逻辑删除功能,如果数据不能删除,可以采用把数据迁移到其它表的办法。

通用枚举

User类中有一个用户状态字段:

在这里插入图片描述

像这种字段我们一般会定义一个枚举,做业务判断的时候就可以直接基于枚举做比较。但是我们数据库采用的是int类型,对应的PO也是Integer。因此业务操作时必须手动把枚举Integer转换,非常麻烦。

因此,MybatisPlus提供了一个处理枚举的类型转换器,可以帮我们把枚举类型与数据库类型自动转换

定义枚举

我们定义一个用户状态的枚举:

在这里插入图片描述

代码如下:

package com.itheima.mp.enums;import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;@Getter
public enum UserStatus {NORMAL(1, "正常"),FROZEN(2, "冻结");private final int value;private final String desc;UserStatus(int value, String desc) {this.value = value;this.desc = desc;}
}

然后把User类中的status字段改为UserStatus 类型:

枚举是直接可以使用==比较的,比较status值的时候就可以看user的status是否为NORMAL或者FREEZE。这样就代码中不会有数字代表状态,使用英文单词代表,代码的可读性也就更好。

在这里插入图片描述

数据库表中存储的status依然存储的是INT类型,但是PO是枚举类型。假如有个枚举对象,里面状态是NORMAL,在save的时候往数据库写的时候不能写NORMAL。反之,查询数据库查到的是INT类型,但是转成PO的时候要用枚举。这就存在Java中的枚举类型与数据库中INT类型的相互转换,不光是枚举类型,Java中的所有类型都需要与数据库中的类型进行转换。这些所有的转换底层都是由Mybatis做的,在Mybatis中有个TypeHandler类型处理器,在ibatis包下,里面由很多的数据类型转换的实现。MP在mybatis的基础上做了拓展,加入了MybatisEnumTypeHandler枚举类型处理器以及AbstractJsonTypeHandler的JSON类型处理器。

要让MybatisPlus处理枚举与数据库类型自动转换,我们必须告诉MybatisPlus,枚举中的哪个字段的值作为数据库值。 MybatisPlus提供了@EnumValue注解来标记枚举属性:

在这里插入图片描述

配置枚举处理器

application.yaml文件中添加配置,使枚举处理器生效:

mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

测试

需要将其他判断状态的字段都改为枚举类型,同时将返回类型UserVO也改为枚举类型。重新启动程序,前端查看status的返回值。

在这里插入图片描述

JsonValue注解

查到的结果是NORMALFROZEN,证明成功查询,枚举的处理也自动处理好了。如何让其返回1、2或者正常、冻结。这与返回值有关,目前返回值改为枚举类型了,枚举在JSON处理的时候,默认以英文名返回。要想让其以value或者desc返回,就需要告诉SpringMVC因为程序的数据往前端返回时是SpringMVC处理的。SpringMVC处理JSON时,底层用的是jackson json包。jackson json提供一些注解用于标记枚举里面的值,把谁返回。添加注解@JsonValuedesc上就返回desc的值,加在value上就返回value的值

在这里插入图片描述

在这里插入图片描述

@Test
void testService() {List<User> list = userService.list();list.forEach(System.out::println);
}

总结

如何实现PO类中的枚举类型变量与数据库字段的转换?

  • 给枚举中的与数据库对应value值添加@EnumValue注解

在这里插入图片描述

  • 在配置文件中配置通用的枚举处理器,实现类型转换
    在这里插入图片描述

枚举在给前端返回的时候默认返回枚举项的名字,不够友好,可以通过@JsonValue自定义返回的值。

在这里插入图片描述

JSON类型处理器

MP除了提供枚举类型处理器外,还提供了JSON类型处理器,它就是解决数据库中JSON类型与Java类型的转换的。

数据库的user表中有一个info字段,是JSON类型:

在这里插入图片描述

格式像这样:

{"age": 20, "intro": "佛系青年", "gender": "male"}

在Java中没有JSON这种数据类型,一般在Java中都是用String类型接收。

而目前User实体类中却是String类型:

在这里插入图片描述

在这种情况下不需要做任何操作,Mybatis就能自动进行Java中字符串MySQL里面的JSON处理。但是在处理业务的时候就比较困难,比如从数据库查出Json数据之后,想要取出某个字段信息就不行,因为在java中是字符串接收的。这样一来,我们要读取info中的属性时就非常不方便。如果要方便获取,info的类型最好是一个Map或者实体类。

而一旦我们把info改为对象类型,就需要在写入数据库时手动转为String,再读取数据库时,手动转换为对象,这会非常麻烦。

因此MybatisPlus提供了很多特殊类型字段的类型处理器,解决特殊字段类型与数据库类型转换的问题。例如处理JSON就可以使用JacksonTypeHandler处理器。

接下来,我们就来看看这个处理器该如何使用。

定义实体

首先,我们定义一个单独实体类来与info字段的属性匹配:

在这里插入图片描述

代码如下:

package com.itheima.mp.domain.po;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor(staticName = "of")
@NoArgsConstructor
public class UserInfo {private Integer age;private String intro;private String gender;
}

使用JSON类型处理器

MP并没有提供在Application.yaml文件里面的全局配置,需要用@TableField注解来处理,在表字段里面设置一个typeHandler属性,在这里指定JacksonTypeHandler,这种配置只针对当前字段有效,如果有好多字段就需要分别指定。同时需要注意将info的类型从String 改为UserInfo

在这里插入图片描述

开启自动ResultMap映射

这是会出现对象的嵌套,User对象里面嵌套了另外一个对象UserInfo,一般对象嵌套都需要定义复杂的resultMap。如果不想定义,就需要在TableName注解上加入属性autoResultMap,默认是关闭的需要开启。

在这里插入图片描述

此时对info赋值需要将之前的json赋值改为用UserInfo里面的静态方法构建。主要主要使用的UserInfo不是糊涂包里的,而是自定义的。

在这里插入图片描述

注意UserVO里面也有info属性,需要将其从String类型转为UserInfo类型。

测试

修改之前的查询结果为json格式

在这里插入图片描述

修改后的查询结果为UserInfo对象

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com