目录
一、接口的实现
二、跨域的处理思路
三、全局异常处理
四、面试题
五、总结
一、接口的实现
1. 查询课程接口
思路:
典型的分页查询 + 按需查询 + 模糊查询的查询
controller:
@ApiOperation(value = "课程列表", notes = "课程列表")
@PostMapping("/list")
public PageResult<CourseBase> courses(PageParams pageParams, @RequestBody CourseBaseInfoDto courseBaseInfoDto) {
PageResult<CourseBase> pageResult = courseBaseService.courses(pageParams, courseBaseInfoDto);
return pageResult;
}
service接口及其实现;
public interface CourseBaseService extends IService<CourseBase> {
PageResult courses(PageParams pageParams, CourseBaseInfoDto courseBaseInfoDto);
}
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase>
implements CourseBaseService{
@Autowired
private CourseMarketService courseMarketService;
@Override
public PageResult<CourseBase> courses(PageParams pageParams, CourseBaseInfoDto courseBaseInfoDto) {
Page<CourseBase> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());
LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.hasText(courseBaseInfoDto.getCourseName()),CourseBase::getName,courseBaseInfoDto.getCourseName());
wrapper.eq(StringUtils.hasText(courseBaseInfoDto.getAuditStatus()),CourseBase::getAuditStatus,courseBaseInfoDto.getAuditStatus());
wrapper.eq(StringUtils.hasText(courseBaseInfoDto.getPublishStatus()),CourseBase::getStatus,courseBaseInfoDto.getPublishStatus());
page(page,wrapper);
List<CourseBase> records = page.getRecords();
PageResult<CourseBase> pageResult = PageResult.ok(records, page.getTotal());
return pageResult;
}
}
2. 查询课程分类接口
典型的对树形数据结构的查询
通过数据库中的parentId字段,就能实现
@Service
public class CourseCategoryServiceImpl extends ServiceImpl<CourseCategoryMapper, CourseCategory>
implements CourseCategoryService{
/**
* 获取分类树
* @return
*/
@Override
public List<CourseCategoryNode> courseCategoryTreeNodes() {
//1. 先查出所有节点
List<CourseCategory> categories = list();
List<CourseCategoryNode> courseCategoryNodes = BeanUtil.copyToList(categories, CourseCategoryNode.class);
List<CourseCategoryNode> collect = Collections.EMPTY_LIST;
if(courseCategoryNodes!=null && courseCategoryNodes.size()>0){
collect = courseCategoryNodes.stream().filter(category-> category.getParentid().equals("1")).map(categoryNode -> {
List<CourseCategoryNode> childrenTreeNodes = children(categoryNode.getId(), courseCategoryNodes);
categoryNode.setChildrenTreeNodes(childrenTreeNodes);
return categoryNode;
}).sorted((category1, category2) -> category1.getOrderby() == null? 0 : category1.getOrderby() - (category2.getOrderby() == null? 0 : category2.getOrderby())).collect(Collectors.toList());
}
return collect;
}
private List<CourseCategoryNode> children(String id, List<CourseCategoryNode> categories) {
List<CourseCategoryNode> collect = Collections.EMPTY_LIST;
//注意判空
if (categories != null && categories.size() > 0) {
//1. 遍历所有节点 找到其节点的一级子节点
collect = categories.stream().filter(category -> category.getParentid().equals(id)).map(category -> {
//2. 再对一级子节点进行递归查找子节点
category.setChildrenTreeNodes(children(category.getId(), categories));
return category;
}).sorted((category1, category2) -> category1.getOrderby() == null? 0 : category1.getOrderby() - (category2.getOrderby() == null? 0 : category2.getOrderby())).collect(Collectors.toList());
}
return collect;
}
}
注意:
1. courseCategoryNodes.stream().filter(category-> category.getParentid().equals("1"))
这个是确保第一级就是 真正的第一级同级 而不会出现 第二级也作为父节点
2. 可以使用map 看似这里其实只是一个简单的set而并没有真正的将其对象进行转换,所以可以直接使用foreach,但是因为这里还有一个sort的后续对流的操作,所以可以使用map,使用map就能连续的对流进行处理
3. 注意避免空指针
要有这种意识,一旦对数组使用stream来操作,数组一定不能为null
还有就是在流处理中,通常可以获取到对象,而去调用对象的get方法,此时就需要主要判空
3. 新增课程信息接口
典型的多表新增 并且必须新增完上一个才能新增下一个也就是关联新增
还有就是新增和修改是一个接口,需要判断是新增还是修改
可以通过标识位判断,另外还可以查看数据库中数据是否存在的方法...老师写的有点问题
这里下面的营销信息是基于上面的基本信息,所以说下面一定是新增
正确的做法应该是再添加一个专门的修改方法
这里建议是不要将修改和添加合并
二、跨域的处理思路
1. 前端使用JSONP的方式
2. 使用过滤器 或者是拦截器 适用于单体服务
拦截器:
@Configuration
public class WebConfig implements WebMvcConfigurer {
/**
* 配置跨域
*
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的路径
registry.addMapping("/**")
// 设置允许跨域请求的域名
.allowedOriginPatterns("*")
// 是否允许cookie
.allowCredentials(true)
// 设置允许的请求方式
.allowedMethods("GET", "POST", "DELETE", "PUT")
// 设置允许的header属性
.allowedHeaders("*")
// 跨域允许时间
.maxAge(3600);
// 设置可被访问的响应头
//.exposedHeaders("jieiwi");
}
}
过滤器:
@Configuration
public class GlobalCorsConfig {
/**
* 允许跨域调用的过滤器
*/
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
//允许白名单域名进行跨域调用
config.addAllowedOrigin("*");
//允许跨越发送cookie
config.setAllowCredentials(true);
//放行全部原始头信息
config.addAllowedHeader("*");
//允许所有请求方法跨域调用
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
还可以添加@CrossOrigin的方式
3. 在网关中配置
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有请求
allowedOrigins: "*" #跨域处理 允许所有的域
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
4. 使用nginx反向代理
由于浏览器直接访问对应的服务会跨域,那么可以不让浏览器直接访问服务,而是先将请求发给nginx,再由nigix代理给对应的服务
其实就是将浏览器环境变成了ngixn环境
因为在nginx中配置前端静态资源是很方便的,那么就可以利用ngixn,直接在浏览器中访问到nginx中的静态资源,这里是不会跨域的,这是由nginx的特点所决定的,nginx本来就可以实现动静分离 然后再在nginx中进行反向代理 将请求代理给服务集群
参考:http://t.csdnimg.cn/i2nS9
三、全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = PriceException.class)
public RestErrorResponse handlePriceException(PriceException e) {
return new RestErrorResponse(e.getMessage());
}
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public RestErrorResponse handleArgsException(MethodArgumentNotValidException e) {
List<String> collect = e.getBindingResult().getFieldErrors().stream().map(fieldError -> {
return fieldError.getField()+fieldError.getDefaultMessage();
}).collect(Collectors.toList());
return new RestErrorResponse(StrUtil.join(",", collect));
}
@ExceptionHandler(value = Exception.class)
public RestErrorResponse handException(){
return new RestErrorResponse(CommonError.UNKOWN_ERROR.getErrMessage());
}
}
这个最终肯定是要返回前端以标准的响应体返回的,这样前端才能拿到异常信息,进行显示
至于这个返回给前端的异常信息到底是怎样的,可以直接 在抛出异常的时候指定好错误,然后在全局异常处理中直接调用异常对象的方法获取到异常信息
return new RestErrorResponse(e.getMessage());
也可以不使用那里的,而是再全局异常中再去自己指定。另外这里的异常信息推荐使用将其封装成枚举 比如下面这样:
return new RestErrorResponse(CommonError.UNKOWN_ERROR.getErrMessage());
反正也就是响应类和枚举类之间的玩法
四、面试题
1. mybais中的分页插件的原理
其实就是将分页参数放到ThreadLocal中,然后根据不同的数据库类型添加对应的分页语句重写sql,例如将select * from table where a=xx 将其重写为 select count(*) from table where a = xx求出总数,然后还有一条select * from table where a = xx limit , 获取到数据
2. 异常处理
使用全局异常处理机制进行处理
@RestControllerAdvice注解和@ExceptionHandle可以处理自定义异常和系统异常 返回自己的异常信息
五、总结
还是几个常见接口的实现 现在来说应该说不能有难度了
分页查询、树形查询....新增和修改....
还是跨域和异常处理 但是学到了更多的处理跨域问题的解决办法
再就是知道mybatis分页插件的原理