目录

 1.创建一个返回统一结果的处理类

2.定义成功失败的枚举

3.自定义异常以及异常处理

4.控制层例子

5.来看前端


构造

ruoyi 前后端分离技术架构 前后端分离流程_ruoyi 前后端分离技术架构

 1.创建一个返回统一结果的处理类

package com.atguigu.eduservice;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.HashMap;
import java.util.Map;

/**
 * 统一返回结果类
 * 调用结果
 * 对success,code,message进行设置->返回调用者的对象方便链式编程->以此继续调用
 */
@Data
public class R {
    @ApiModelProperty(value = "是否成功")
    private Boolean success;

    @ApiModelProperty(value = "返回码")
    private Integer code;

    @ApiModelProperty(value = "返回消息")
    private String message;

    @ApiModelProperty(value = "返回数据")
    private Map<String, Object> data = new HashMap<String, Object>();

    //设置一个私有构造让别人不能修改我的属性和方法,只能用规定的static成员
    private R() {
    }

    public static R ok(){
        R r = new R();
        r.setSuccess(true);
        r.setCode(ResultCode.SUCCESS);
        r.setMessage("成功");
        return r;
    }

    public static R error(){
        R r = new R();
        r.setSuccess(false);
        r.setCode(ResultCode.ERROR);
        r.setMessage("失败");
        return r;
    }

    /**
     * 对状态码以及信息(success,code,data)进行设置
     * @param success
     * @return
     */
    public R success(Boolean success){
        this.setSuccess(success);
        return this;
    }

    public R message(String message){
        this.setMessage(message);
        return this;
    }

    public R code(Integer code){
        this.setCode(code);
        return this;
    }

    public R data(String key, Object value){
        this.data.put(key, value);
        return this;
    }

    public R data(Map<String, Object> map){
        this.setData(map);
        return this;
    }
}

2.定义成功失败的枚举

package com.atguigu.eduservice;

public interface ResultCode {
//定义成功失败的编码
    public static Integer SUCCESS = 20000;

    public static Integer ERROR = 20001;
}

3.自定义异常以及异常处理

ruoyi 前后端分离技术架构 前后端分离流程_spring_02

 自定义异常类

package com.atguigu.eduservice.exceptionHandler;

import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
/**
 * 自定义异常
 */
public class GuliException extends RuntimeException{

    @ApiModelProperty(value = "状态码")
    private Integer code;
    private String msg;

}

 统一异常处理类

核心:@ControllerAdvice+@Slf4j+@ExceptionHandler(xxx.class)

package com.atguigu.eduservice.exceptionHandler;

import com.atguigu.eduservice.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 统一异常处理类
 */
@ControllerAdvice
@Slf4j//logback日志
public class GlobalExceptionHandler {

    @ResponseBody
    @ExceptionHandler(Exception.class)//指定在哪里出现的异常会被处理
    public R GlobalError(Exception e) {
        e.printStackTrace();
        return R.error().message("执行全局异常处理");
    }


    /**
     * 优先执行特定异常
     * 特定异常处理
     */
    @ResponseBody
    @ExceptionHandler(ArithmeticException.class)//指定在哪里出现的异常会被处理
    public R ArithmeticError(Exception e) {
        e.printStackTrace();
        return R.error().message("ArithmeticException出现");
    }

    /**
     * 自定义异常
     */
    @ExceptionHandler
    @ResponseBody
    public R error(GuliException e) {
        //会把日志信息写到文件中
        log.error(e.getMsg());

        e.printStackTrace();
        return R.error().message(e.getMsg()).code(e.getCode());
    }
}

对字段进行填充

package com.atguigu.eduservice.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.nio.channels.NetworkChannel;
import java.util.Date;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    /**
     * 对插入字段进行自动填充->这里就是创建时间和修改时间我们会自动填充
     *
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("gmtCreate", new Date(), metaObject);
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }
}

4.控制层例子

package com.atguigu.eduservice.controller;


import com.atguigu.eduservice.R;
import com.atguigu.eduservice.entity.EduTeacher;
import com.atguigu.eduservice.entity.vo.TeacherQuery;
import com.atguigu.eduservice.service.EduTeacherService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;

/**
 * <p>
 * 讲师 前端控制器
 * </p>
 * http://localhost:8001/eduservice/edu-teacher/findAll
 *
 * @author testjava
 * @since 2022-07-05
 */
@Api(description = "讲师管理")
@RestController
@CrossOrigin
@RequestMapping("/eduservice/teacher")
public class EduTeacherController {

    @Autowired
    private EduTeacherService teacherService;

    /**
     * 1.查询教师表中所有数据
     * SELECT id,name,intro,career,level,avatar,sort,is_deleted,gmt_create,gmt_modified FROM edu_teacher WHERE is_deleted=0
     */
    @ApiOperation(value = "所有讲师")
    @GetMapping("findAll")
    public R findAllTeacher() {
        List<EduTeacher> list = teacherService.list(null);
        return R.ok().data("items", list);
    }

    /**
     * 2.逻辑删除讲师的方法:rest风格来一手
     */
    @ApiOperation(value = "根据逻辑删除讲师")
    @DeleteMapping("{id}")
    public R removeTeacher(@PathVariable String id) {
        boolean flag = teacherService.removeById(id);
        System.out.println("删除成功:" + flag);

        //具体判断进行返回
        if (flag) {
            return R.ok();
        } else {
            return R.error();
        }
    }


    /**
     * 3.分页查询讲师
     * SELECT id,name,intro,career,level,avatar,sort,is_deleted,gmt_create,gmt_modified FROM edu_teacher WHERE is_deleted=0 LIMIT 0,3
     */
    @GetMapping("pageTeacher/{current}/{limit}")
    public R pageListTeacher(@PathVariable long current, @PathVariable long limit) {

        //创建page对象
        Page<EduTeacher> teacherPage = new Page<>(current, limit);

        //调用方法进行分页,会将分页的数据封装到teacherPage里面
        teacherService.page(teacherPage, null);

        //总记录数
        long total = teacherPage.getTotal();
        //得到分页后数据集合
        List<EduTeacher> records = teacherPage.getRecords();

        HashMap map = new HashMap();
        map.put("total", total);
        map.put("rows", records);

        return R.ok().data(map);
    }

    /**
     * 4.多条件组合查询
     * 讲师级别,入住时间,名称...
     * 多条件:我们可以将条件值传入对象中,然后将对象传递到接口中(vo)
     * PageHelper的话调用startPage然后封装到PageInfo下即可
     * 这里的TeacherQuery也可以用@RequestBody来传递数据->Post提交
     * 传递的为Json数据,将Json数据封装到对象里面
     * SELECT id,name,intro,career,level,avatar,sort,is_deleted,gmt_create,gmt_modified FROM edu_teacher WHERE is_deleted=0 ORDER BY gmt_create DESC LIMIT 0,3      */
    @PostMapping("pageTeacherCondition/{current}/{limit}")
    public R pageTeacherCondition(@PathVariable long current, @PathVariable long limit, @RequestBody(required = false) TeacherQuery teacherQuery) {

        //创建Page对象
        Page<EduTeacher> teacherPage = new Page<>(current, limit);

        //wrapper构建条件过滤
        QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();

        String name = teacherQuery.getName();
        Integer level = teacherQuery.getLevel();
        String begin = teacherQuery.getBegin();
        String end = teacherQuery.getEnd();

        wrapper.like(StringUtils.isNotBlank(name), "name", name)
                .like(level != null, "level", level)
                .ge(begin != null, "gmt_create", begin)
                .le(end != null, "gmt_create", end);

        //按照时间降序处理
        wrapper.orderByDesc("gmt_create");

        //对过滤条件进行封装进而->得到分页数据
        teacherService.page(teacherPage, wrapper);
        long total = teacherPage.getTotal();
        List<EduTeacher> records = teacherPage.getRecords();

        return R.ok().data("total", total).data("rows", records);
    }


    /**
     *5.添加讲师
     */
    @ApiOperation(value = "添加讲师")
    @PostMapping("addTeacher")
    public R addTeacher(@RequestBody EduTeacher eduTeacher){
        boolean save = teacherService.save(eduTeacher);
        return save?R.ok():R.error();
    }

    /**
     * 6.修改讲师
     * 根据讲师id先进行查询,然后修改
     * UPDATE edu_teacher SET name=?, intro=?, career=?, level=?, avatar=?, sort=?, gmt_modified=? WHERE id=? AND is_deleted=0
     */
    @GetMapping("getTeacher/{id}")
    public R getTeacher(@PathVariable String id){
        EduTeacher eduTeacher = teacherService.getById(id);
        return R.ok().data("teacher",eduTeacher);
    }

    @ApiOperation(value = "修改讲师")
    @PostMapping("updateTeacher")
    public R updateTeacher(@RequestBody EduTeacher eduTeacher){
        boolean flag = teacherService.updateById(eduTeacher);
        if(flag){
            return R.ok();
        }else{
            return R.error();
        }
    }



}

返回我们的json数据

5.来看前端

ruoyi 前后端分离技术架构 前后端分离流程_java_03

5.1在我们的config下配置了路由信息dev.env.js

ruoyi 前后端分离技术架构 前后端分离流程_java_04

 

 9001是我们nginx负载均衡的端口

'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  // BASE_API: '"https://easy-mock.com/mock/5950a2419adc231f356a6636/vue-admin"',
  BASE_API: '"http://localhost:9001"',
})

5.2定义我们的后台api

ruoyi 前后端分离技术架构 前后端分离流程_java_05

 里面调用了我们后台的接口

import request from '@/utils/request'

export default {
    //1.讲师列表(条件查询分页)
    //参数分别为当前页,每页记录数,
    getTeacherListPage(current,limit,teacherQuery) {
        return request({
            url: `/eduservice/teacher/pageTeacherCondition/${current}/${limit}`,

            method: 'post',
            //teacherQuery条件对象,后端使用RequestBody传输数据
            //data表示对象传唤成json传输
            data: teacherQuery
          })
    },
    deleteTeacherId(id){
        return request({
            url: `/eduservice/teacher/${id}`,

            method: 'delete'
            //teacherQuery条件对象,后端使用RequestBody传输数据
            //data表示对象传唤成json传输
            // data: teacherQuery
          })
    },
    addTeacher(teacher){
        return request({
            url: '/eduservice/teacher/addTeacher',
            method: 'post',
            //将teacher转为json传输数据
            data: teacher
        })
    },
    getTeacherInfo(id){
        return request({
            url: `/eduservice/teacher/getTeacher/${id}`,
            method: 'get'
        })
    },
    //修改讲师
    updateTeacherInfo(teacher){
       return request({
        url: `/eduservice/teacher/updateTeacher`,
        method: 'post',
        data: teacher
       }) 
    },
     //2.查询所有的讲师
    getListTeacher(){
    return request({
      url: `/eduservice/teacher/findAll`,
      method: 'get'
    })
  }
}

5.3然后再在具体页面调用封装后台接口的js文件,调用里面的方法

<script>
//引入teacher.js文件
import teacher from '@/api/edu/teacher'

export default{
  //核心代码位置
  data(){//定义变量和初始值
   return {
    list:null,//查询后的接口返回值
    page:1,
    limit:10,
    total:0,//总记录数
    teacherQuery:{

    }//条件封装的对象
   }
  },
  created(){//页面渲染前,调用methods定义的方法
     //调用
     this.getList()
  },
  
  methods:{ //创建具体的方法
     //讲师列表的方法
     getList(page=1) {
      this.page=page
      teacher.getTeacherListPage(this.page,this.limit,this.teacherQuery)
             .then(response=>{//请求成功
               //response返回接口数据
              //  console.log(response)
              this.list=response.data.rows
              this.total=response.data.total
              console.log(this.list)
              console.log(this.total)
             }) 
             .catch(error=>{
               console.log(error)
             }) //失败
     },

     resetData(){//清空的方法
       //表单输入数据清空
       this.teacherQuery={}

       //查询所有讲师的数据
       this.getList()
     },

     //删除讲师的方法
    removeDataById(id) {
    // debugger
    // console.log(memberId)
    this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
    }).then(() => {//点击确定,删除then方法
      teacher.deleteTeacherId(id)
       .then(response => {//删除成功
        //提示信息
        this.$message({
          type: 'success',
          message: '删除成功!'
        });
        //回到列表页面
        this.getList()
        })
        // 点击取消
    })
 }

  }

}

6.nginx中的配置

监听9001端口根据名称进行路由

server {
      listen 9001;
      server_name localhost;

      location ~ /eduservice/ {           
       proxy_pass http://localhost:8001;
      }

      location ~ /eduoss/ {           
       proxy_pass http://localhost:8002;
      }
    
      location ~ /eduvod/ {           
       proxy_pass http://localhost:8003;
      }

      location ~ /educms/ {
        proxy_pass http://localhost:8004;
      }

       location ~ /educenter/ {
        proxy_pass http://localhost:8006;
      }

       location ~ /edumsm/ {
        proxy_pass http://localhost:8005;
      }
    }