• 学成在线第二天-查询课程、查询课程分类、新增课程接口实现以及跨域的处理思路和全局异常处理的使用以及面试题


    目录

    一、接口的实现

    二、跨域的处理思路

    三、全局异常处理

    四、面试题

    五、总结


    一、接口的实现

    1. 查询课程接口

    思路:

    典型的分页查询 + 按需查询 + 模糊查询的查询

    controller:

    1. @ApiOperation(value = "课程列表", notes = "课程列表")
    2. @PostMapping("/list")
    3. public PageResult courses(PageParams pageParams, @RequestBody CourseBaseInfoDto courseBaseInfoDto) {
    4. PageResult pageResult = courseBaseService.courses(pageParams, courseBaseInfoDto);
    5. return pageResult;
    6. }

    service接口及其实现;

    1. public interface CourseBaseService extends IService {
    2. PageResult courses(PageParams pageParams, CourseBaseInfoDto courseBaseInfoDto);
    3. }
    1. @Service
    2. public class CourseBaseServiceImpl extends ServiceImpl
    3. implements CourseBaseService{
    4. @Autowired
    5. private CourseMarketService courseMarketService;
    6. @Override
    7. public PageResult courses(PageParams pageParams, CourseBaseInfoDto courseBaseInfoDto) {
    8. Page page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());
    9. LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
    10. wrapper.like(StringUtils.hasText(courseBaseInfoDto.getCourseName()),CourseBase::getName,courseBaseInfoDto.getCourseName());
    11. wrapper.eq(StringUtils.hasText(courseBaseInfoDto.getAuditStatus()),CourseBase::getAuditStatus,courseBaseInfoDto.getAuditStatus());
    12. wrapper.eq(StringUtils.hasText(courseBaseInfoDto.getPublishStatus()),CourseBase::getStatus,courseBaseInfoDto.getPublishStatus());
    13. page(page,wrapper);
    14. List records = page.getRecords();
    15. PageResult pageResult = PageResult.ok(records, page.getTotal());
    16. return pageResult;
    17. }
    18. }

    2. 查询课程分类接口

    典型的对树形数据结构的查询

    通过数据库中的parentId字段,就能实现

    1. @Service
    2. public class CourseCategoryServiceImpl extends ServiceImpl
    3. implements CourseCategoryService{
    4. /**
    5. * 获取分类树
    6. * @return
    7. */
    8. @Override
    9. public List courseCategoryTreeNodes() {
    10. //1. 先查出所有节点
    11. List categories = list();
    12. List courseCategoryNodes = BeanUtil.copyToList(categories, CourseCategoryNode.class);
    13. List collect = Collections.EMPTY_LIST;
    14. if(courseCategoryNodes!=null && courseCategoryNodes.size()>0){
    15. collect = courseCategoryNodes.stream().filter(category-> category.getParentid().equals("1")).map(categoryNode -> {
    16. List childrenTreeNodes = children(categoryNode.getId(), courseCategoryNodes);
    17. categoryNode.setChildrenTreeNodes(childrenTreeNodes);
    18. return categoryNode;
    19. }).sorted((category1, category2) -> category1.getOrderby() == null? 0 : category1.getOrderby() - (category2.getOrderby() == null? 0 : category2.getOrderby())).collect(Collectors.toList());
    20. }
    21. return collect;
    22. }
    23. private List children(String id, List categories) {
    24. List collect = Collections.EMPTY_LIST;
    25. //注意判空
    26. if (categories != null && categories.size() > 0) {
    27. //1. 遍历所有节点 找到其节点的一级子节点
    28. collect = categories.stream().filter(category -> category.getParentid().equals(id)).map(category -> {
    29. //2. 再对一级子节点进行递归查找子节点
    30. category.setChildrenTreeNodes(children(category.getId(), categories));
    31. return category;
    32. }).sorted((category1, category2) -> category1.getOrderby() == null? 0 : category1.getOrderby() - (category2.getOrderby() == null? 0 : category2.getOrderby())).collect(Collectors.toList());
    33. }
    34. return collect;
    35. }
    36. }

    注意:

    1. courseCategoryNodes.stream().filter(category-> category.getParentid().equals("1"))

    这个是确保第一级就是 真正的第一级同级  而不会出现  第二级也作为父节点

    2. 可以使用map 看似这里其实只是一个简单的set而并没有真正的将其对象进行转换,所以可以直接使用foreach,但是因为这里还有一个sort的后续对流的操作,所以可以使用map,使用map就能连续的对流进行处理

    3. 注意避免空指针

    要有这种意识,一旦对数组使用stream来操作,数组一定不能为null

    还有就是在流处理中,通常可以获取到对象,而去调用对象的get方法,此时就需要主要判空

    3. 新增课程信息接口

    典型的多表新增  并且必须新增完上一个才能新增下一个也就是关联新增

    还有就是新增和修改是一个接口,需要判断是新增还是修改

    可以通过标识位判断,另外还可以查看数据库中数据是否存在的方法...老师写的有点问题

    这里下面的营销信息是基于上面的基本信息,所以说下面一定是新增

    正确的做法应该是再添加一个专门的修改方法

    这里建议是不要将修改和添加合并

    二、跨域的处理思路

    1. 前端使用JSONP的方式

    2. 使用过滤器 或者是拦截器 适用于单体服务

    拦截器:

    1. @Configuration
    2. public class WebConfig implements WebMvcConfigurer {
    3. /**
    4. * 配置跨域
    5. *
    6. * @param registry
    7. */
    8. @Override
    9. public void addCorsMappings(CorsRegistry registry) {
    10. // 设置允许跨域的路径
    11. registry.addMapping("/**")
    12. // 设置允许跨域请求的域名
    13. .allowedOriginPatterns("*")
    14. // 是否允许cookie
    15. .allowCredentials(true)
    16. // 设置允许的请求方式
    17. .allowedMethods("GET", "POST", "DELETE", "PUT")
    18. // 设置允许的header属性
    19. .allowedHeaders("*")
    20. // 跨域允许时间
    21. .maxAge(3600);
    22. // 设置可被访问的响应头
    23. //.exposedHeaders("jieiwi");
    24. }
    25. }

    过滤器:

    1. @Configuration
    2. public class GlobalCorsConfig {
    3. /**
    4. * 允许跨域调用的过滤器
    5. */
    6. @Bean
    7. public CorsFilter corsFilter() {
    8. CorsConfiguration config = new CorsConfiguration();
    9. //允许白名单域名进行跨域调用
    10. config.addAllowedOrigin("*");
    11. //允许跨越发送cookie
    12. config.setAllowCredentials(true);
    13. //放行全部原始头信息
    14. config.addAllowedHeader("*");
    15. //允许所有请求方法跨域调用
    16. config.addAllowedMethod("*");
    17. UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    18. source.registerCorsConfiguration("/**", config);
    19. return new CorsFilter(source);
    20. }
    21. }

     还可以添加@CrossOrigin的方式

    3. 在网关中配置

    1. gateway:
    2. globalcors:
    3. cors-configurations:
    4. '[/**]': # 匹配所有请求
    5. allowedOrigins: "*" #跨域处理 允许所有的域
    6. allowedMethods: # 支持的方法
    7. - GET
    8. - POST
    9. - PUT
    10. - DELETE

    4. 使用nginx反向代理

    由于浏览器直接访问对应的服务会跨域,那么可以不让浏览器直接访问服务,而是先将请求发给nginx,再由nigix代理给对应的服务

    其实就是将浏览器环境变成了ngixn环境

    因为在nginx中配置前端静态资源是很方便的,那么就可以利用ngixn,直接在浏览器中访问到nginx中的静态资源,这里是不会跨域的,这是由nginx的特点所决定的,nginx本来就可以实现动静分离 然后再在nginx中进行反向代理  将请求代理给服务集群

     参考:http://t.csdnimg.cn/i2nS9

    三、全局异常处理

    1. @RestControllerAdvice
    2. public class GlobalExceptionHandler {
    3. @ExceptionHandler(value = PriceException.class)
    4. public RestErrorResponse handlePriceException(PriceException e) {
    5. return new RestErrorResponse(e.getMessage());
    6. }
    7. @ExceptionHandler(value = MethodArgumentNotValidException.class)
    8. public RestErrorResponse handleArgsException(MethodArgumentNotValidException e) {
    9. List collect = e.getBindingResult().getFieldErrors().stream().map(fieldError -> {
    10. return fieldError.getField()+fieldError.getDefaultMessage();
    11. }).collect(Collectors.toList());
    12. return new RestErrorResponse(StrUtil.join(",", collect));
    13. }
    14. @ExceptionHandler(value = Exception.class)
    15. public RestErrorResponse handException(){
    16. return new RestErrorResponse(CommonError.UNKOWN_ERROR.getErrMessage());
    17. }
    18. }

    这个最终肯定是要返回前端以标准的响应体返回的,这样前端才能拿到异常信息,进行显示

    至于这个返回给前端的异常信息到底是怎样的,可以直接 在抛出异常的时候指定好错误,然后在全局异常处理中直接调用异常对象的方法获取到异常信息

    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分页插件的原理

  • 相关阅读:
    数据库——事务
    分享119个ASP.NET源码总有一个是你想要的
    【NLP教程】用python调用百度AI开放平台进行情感倾向分析
    【Python笔记-设计模式】装饰器模式
    PostgreSQL修炼之道笔记之基础篇(十一)
    zookeeper:服务器有几种状态?
    WPF的UI布局
    剑指 Offer 50. 第一个只出现一次的字符
    红包雨中:Redis 和 Lua 的邂逅
    【后端】Ubuntu开放mysql端口访问;如何开放服务器mysql给其他ip使用;在Ubuntu/Linux环境下开放3306端口
  • 原文地址:https://blog.csdn.net/m0_63445035/article/details/133968869