前言:主要介绍最基础的springboot开发架构
目录
- 1. overall
- 2. 配置文件
- 2.1 YAML
- 2.2 properties
- 2.3 配置文件加载顺序
- 2.4 多配置文件
- 3. 代码包
- 3.1 infrastructure
- 3.1.1 persistence
- 3.2 application
- 3.2.1 dto
- 3.2.2 converter
- 3.2.3 service
- 3.3 api
- 3.3.1 vo
- 3.3.2 req
- 3.3.3 converter
- 3.3.4 controller
- **结语**
1. overall
核心部分主要是src包,main包存放的是后端代码,test是用于测试main包的代码。main包主要包含以下几个部分:
- java:存放后端代码
- resources:存放配置文件
- webapp:存放资源文件,如前端jsp、图片资源等
2. 配置文件
springboot使用固定名字的配置文件:application.properties或application.yml。
2.1 YAML
基本语法
- 使用缩进表示层级关系
- 缩进时不允许使用Tab键,只允许使用空格
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
- 大小写敏感
yml举例:
server:port: 8080
2.2 properties
properties举例:
spring.application.name=apply
2.3 配置文件加载顺序
- 按目录。位置高的将覆盖位置低的。
- application.properties 的优先级高于 application.yml
- 互补读取:
- 如果优先级高的配置文件中没有某个配置项,则会到优先级低的配置文件中找该配置项,即具有互补功能。
- 文件名相同才会互补
2.4 多配置文件
有时候为了分开produce和test配置,会使用多个配置文件。
这种情况下可以在application.yml文件中指定使用的配置文件:
3. 代码包
代码包的路径为:
其中buildbaseframe为项目名。
后端代码主要包含以下几个部分:
- BuildBaseFrameApplication: 启动类
- utils:工具代码包
- infrastructure
- application
- api
3.1 infrastructure
对应数据访问层,主要包含:
- common包: 底层的一些公共配置
- 模块包: 如用户模块
本节主要对各个模块包进行说明。
3.1.1 persistence
数据持久化层,主要包括mysql和repository。
- mysql
主要是用来和数据库做绑定,映射对象到PO。
xml文件固定格式为:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.buildbaseframe.infrastructure.user.persistence.mysql.mapper.UserPoMapper"><select id="findThis" resultType="com.example.buildbaseframe.infrastructure.user.persistence.repository.po.UserPo">select *from t_userwhere id = #{id}</select>
</mapper>
namespace是为了绑定mysql包下对应的映射文件,下写各种sql操作语句。
xxxPoMapper文件是为了做数据库对象和PO对象的映射,举例:
@Mapper
public interface UserPoMapper extends BaseMapper<UserPo> {/*** 测试xml方式绑定查询*/UserPo findThis(@Param("id") Long id);}
- PoMapper文件只需要写一个接口继承自BaseMapper,类型名为同名的Po类(自定义)
- PoMapper文件的方法名和xml文件中的操作id需要一致
- @Param传入参数也需要和xml对应
- repository
主要操作PO对象。
PO包
将数据库表结构映射到JAVA,举例:
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@TableName("t_user")
public class UserPo extends BaseDatabasePo {private static final long serialVersionUID = 1L;/*** 用户昵称*/@TableField(value = "name")private String nickname;/*** 用户头像url*/@TableField(value = "avatar_url")private String avatarUrl;/*** 用户个人介绍*/@TableField(value = "description")private String introduction;/*** 用户性别*/@TableField(value = "gender")private Integer gender;}
由于对PO对象有一些公共操作,通常先在common包中写一个公共类:
@Data
@EqualsAndHashCode(exclude = {"createTime", "updateTime"})
public class BaseDatabasePo implements Serializable {/*** 主键ID*/@TableId(value = "id", type = IdType.ASSIGN_ID)protected Long id;/*** 创建时间*/@TableFieldprotected LocalDateTime createTime;/*** 更新时间*/@TableFieldprotected LocalDateTime updateTime;}
repository接口
主要包含一些对数据对象的最基本的操作方法。举例:
public interface UserRepository {public UserPo get(Long userId);public int update(UserPo po, Long userId);public Long insertOneUser(UserPo userPo);
}
repository实现类
主要是对接口类的实现。
@Repository
public class UserRepositoryImpl implements UserRepository {@Autowiredprivate UserPoMapper mapper;@Overridepublic UserPo get(Long userId) {return mapper.selectById(userId);}@Overridepublic int update(UserPo po, Long userId) {UpdateWrapper<UserPo> wrapper = new UpdateWrapper<>();wrapper.eq("id", userId);if (po.getNickname() != null)wrapper.set("nickname", po.getNickname());if (po.getAvatarUrl() != null)wrapper.set("avatar_url", po.getAvatarUrl());if (po.getIntroduction() != null)wrapper.set("introduction", po.getIntroduction());if (po.getGender() != null)wrapper.set("gender", po.getGender());return mapper.update(po, wrapper);}@Overridepublic Long insertOneUser(UserPo userPo){mapper.insert(userPo);return userPo.getId();}
}
- 先注入PoMapper对象,用于调用各种对数据库底层的操作
3.2 application
对应应用层,主要结构如下:
- common包:公共配置,主要涉及到一些exception的处理
- 各模块包
主要讲解各模块包,结构如下,其中dto、converter、service是必须的:
3.2.1 dto
前端给后端传递的数据,举例:
@Data
public class UserInfoDto {/*** 用户id*/private Long id;/*** 用户昵称*/private String nickname;/*** 用户头像url*/private String avatarUrl;/*** 用户个人介绍*/private String introduction;/*** 用户性别*/private GenderEnum gender;}
3.2.2 converter
只用写接口,具体方法会自动实现。用来实现Po和Dto对象之间的转换。
@Mapper(componentModel = "spring")
public interface UserAppConverter {UserInfoDto toUserInfoDto(UserPo po);UserPo toUserPo(UserInfoDto dto);}
3.2.3 service
服务层的接口和实现,用来实现和数据访问层的交互。
接口
public interface UserService {public UserInfoDto getUserInfo(Long userId);public UserInfoDto updateUserInfo(UserInfoDto dto, Long userId);public Long insertOneUser(UserInfoDto userInfoDto);
}
实现类
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserRepository userRepository;@Autowiredprivate UserAppConverter userAppConverter;/*** 根据id获取用户信息* @param userId* @return*/@Overridepublic UserInfoDto getUserInfo(Long userId) {UserPo po = userRepository.get(userId);if (po == null) {throw new NotFoundException("用户信息");}System.out.println(po);return userAppConverter.toUserInfoDto(po);}/*** 更新用户信息* @param dto* @param userId* @return* @throws NotFoundException*/@Overridepublic UserInfoDto updateUserInfo(UserInfoDto dto, Long userId){UserPo po = userAppConverter.toUserPo(dto);if (userRepository.get(userId) == null) {throw new NotFoundException("用户信息");}int succ = userRepository.update(po, userId);return userAppConverter.toUserInfoDto(userRepository.get(userId));}/*** 添加新用户* @param userInfoDto* @return*/@Overridepublic Long insertOneUser(UserInfoDto userInfoDto){UserPo userPo = userAppConverter.toUserPo(userInfoDto);UserPo userPo1 = userRepository.findByName(userPo.getNickname());if(userPo1!=null){throw new BusinessException(ExceptionType.DUPLICATE_ERROR);}Long id = userRepository.insertOneUser(userPo);return id;}}
3.3 api
控制器层,目录结构如下:
- common包:公共类,包括异常捕获、权限、page验证等功能
- 各模块包
主要讲解模块包,结构如下:
3.3.1 vo
数据视图对象,后端传给前端的数据。
@Data
public class UserInfoVo {/*** 用户id*/private String id;/*** 用户昵称*/private String nickname;/*** 用户头像url*/private String avatarUrl;/*** 用户个人介绍*/private String introduction;/*** 用户性别*/private String gender;}
3.3.2 req
对vo对象做检查。
@Data
public class UserCreateReq {/*** 用户昵称*/@Length(min = 2, max = 64, message = "昵称长度应在2-64之间")private String nickname;/*** 用户头像url*/@URL(message = "头像应当是有效的图片url")@Length(max = 255, message = "头像URL长度不能超过255")private String avatarUrl;/*** 用户个人介绍*/@Length(max = 255, message = "用户介绍长度不能超过255")private String introduction;/*** 用户性别*/@EnumStringValidate(value = GenderEnum.class, message = "不是有效的性别类型")private String gender;}
3.3.3 converter
dto和vo对象的转换。
@Mapper(componentModel = "spring")
public interface UserApiConverter{@Mapping(source = "introduction", target = "description")UserInfoVo toUserInfoVo(UserInfoDto dto);@Mapping(source = "description", target = "introduction")UserInfoDto toUserInfoDto(UserCreateReq req);}
3.3.4 controller
api的实现。
@Validated
@RestController // 既需要返回html数据又需要返回非html数据,类上使用@controller,方法上@requestcontroller或@responsebody
@Slf4j
@RequestMapping("/api/v1/user")
public class UserController {@Autowiredprivate UserService service;@Autowiredprivate UserApiConverter userApiConverter;@Autowiredprivate GenderEnumConverter genderEnumConverter;/*** 用户获得自己的基本信息** @param* @return* @methodName getOwnInfo*/// 可以不用返回CommonResullt,有包装器会拦截@RequestMapping(value = "/info/own", method = RequestMethod.GET)public UserInfoVo getOwnInfo() {return userApiConverter.toUserInfoVo(service.getUserInfo(SecurityContextHolder.getUserId()));}/*** 根据id获得用户信息** @param* @return* @methodName getUserInfo*/@RequestMapping(value = "/info/{userId}", method = RequestMethod.GET)public UserInfoVo getUserInfo(@PathVariable("userId") String userId) {return userApiConverter.toUserInfoVo(service.getUserInfo(Long.valueOf(userId)));}}
结语
以上是关于springboot的一个基本框架的梳理,具体细节方面的实现需要根据实际需求修改。