最近总部的漏洞扫描团队天天对我们的系统进行SQL注入,登陆破解..等等,搞得表示压力山大,其中对我们 的滑块验证码存在绕过登陆问题发报,最终把账号、密码登陆下线,今天终于把这块的bug进行修复了,先看效果:

第一步:弹出框架子模块_src/components/loginmove/slide-verify.vue

<template>
    <div class="slide-verify" id="slideVerify" :style="widthlable" onselectstart="return false;">
        <canvas :width="w" :height="h" ref="canvas" ></canvas>

        <canvas :width="w" :height="h" ref="block"  class="slide-verify-block"></canvas>
       <div @click="refresh" class="slide-verify-refresh-icon"></div>
       container -->
        <div class="slide-verify-slider" :style="widthlable" :class="{'container-active': containerActive, 'container-success': containerSuccess, 'container-fail': containerFail}">
            <div class="slide-verify-slider-mask" :style="{width: sliderMaskWidth}">
                <!-- slider -->
                <div @mousedown="sliderDown"
                    @touchstart="touchStartEvent"
                    @touchmove="touchMoveEvent"
                    @touchend="touchEndEvent"
                    class="slide-verify-slider-mask-item"
                    :style="{left: sliderLeft}">
                    <div class="slide-verify-slider-mask-item-icon"></div>
                </div>
            </div>
            <span class="slide-verify-slider-text">{{sliderText}}</span>
        </div>
    </div>
</template>
<script>
    const PI = Math.PI;

    function sum(x, y) {
        return x + y
    }

    function square(x) {
        return x * x
    }
    export default {
        name: 'SlideVerify',
        props: {
            // block length
            l: {
                type: Number,
                default: 42,
            },
            // block radius
            r: {
                type: Number,
                default: 10,
            },
            // canvas width
            w: {
                type: Number,
                default: 310,
            },
            // canvas height
            h: {
                type: Number,
                default: 155,
            },
           block_x: {
            type: Number,
            default: 155,
            },
          block_y: {
            type: Number,
            default: 20,
          },
          sliderText: {
                type: String,
                default: 'Slide filled right',
            },
          imgurl: {
            type: String,
            default: '',
          },
          miniimgurl: {
            type: String,
            default: '',
          },

        },
        data() {
            return {
                containerActive: false, // container active class
                containerSuccess: false, // container success class
                containerFail: false, // container fail class
                canvasCtx: null,
                blockCtx: null,
                block: null,
                canvasStr: null,
                //block_x: undefined, // container random position
                // block_y: undefined,
                L: this.l + this.r * 2 + 3, // block real lenght
                img: undefined,
                originX: undefined,
                originY: undefined,
                isMouseDown: false,
                trail: [],
              widthlable:'',
                sliderLeft: 0, // block right offset
                sliderMaskWidth: 0, // mask width
            }
        },
        mounted() {
          //随机生成数this.block_x =
            this.init()
        },
        methods: {
            init() {
                this.initDom()
                this.bindEvents()
                this.widthlable ='width:'+this.w+'px;'
            },
            initDom() {
                this.block = this.$refs.block;
                 this.canvasStr = this.$refs.canvas;

                this.canvasCtx = this.canvasStr.getContext('2d')
                this.blockCtx = this.block.getContext('2d')
            },
            initImg(h) {
              var that = this
              const img = document.createElement('img');
              img.onload = onload;
              img.onerror = () => {
                img.src = that.imgurl
              }
              img.src = that.imgurl
              img.onload = function(){
                that.canvasCtx.drawImage(img, 0, 0, that.w, that.h)
              }

              this.img=img
              const img1 = document.createElement('img');
              var  blockCtx = that.blockCtx
              var block_y = h||that.block_y
              img1.onerror = () => {
                img1.src = that.miniimgurl
              }
              img1.src = that.miniimgurl
              img1.onload = function(){
                blockCtx.drawImage(img1, 0, block_y, 61, 61)
              }
            },
            refresh() {
                this.$emit('refresh')
            },
            sliderDown(event) {
                this.originX = event.clientX;
                this.originY = event.clientY;
                this.isMouseDown = true;
            },
            touchStartEvent(e) {
                this.originX = e.changedTouches[0].pageX;
                this.originY = e.changedTouches[0].pageY;
                this.isMouseDown = true;
            },
            bindEvents() {
                document.addEventListener('mousemove', (e) => {
                    if (!this.isMouseDown) return false;
                    const moveX = e.clientX - this.originX;
                    const moveY = e.clientY - this.originY;
                    if (moveX < 0 || moveX + 38 >= this.w) return false;
                    this.sliderLeft = moveX + 'px';
                    let blockLeft = (this.w - 40 - 20) / (this.w - 40) * moveX;
                    this.block.style.left = blockLeft + 'px';

                    this.containerActive = true; // add active
                    this.sliderMaskWidth = moveX + 'px';
                    this.trail.push(moveY);
                });
                document.addEventListener('mouseup', (e) => {
                    if (!this.isMouseDown) return false
                    this.isMouseDown = false
                    if (e.clientX === this.originX) return false;
                    this.containerActive = false; // remove active
                    this.verify()

                })
            },
            touchMoveEvent(e) {
                if (!this.isMouseDown) return false;
                const moveX = e.changedTouches[0].pageX - this.originX;
                const moveY = e.changedTouches[0].pageY - this.originY;
                if (moveX < 0 || moveX + 38 >= this.w) return false;
                this.sliderLeft = moveX + 'px';
                let blockLeft = (this.w - 40 - 20) / (this.w - 40) * moveX;
                this.block.style.left = blockLeft + 'px';

                this.containerActive = true;
                this.sliderMaskWidth = moveX + 'px';
                this.trail.push(moveY);
            },
            touchEndEvent(e) {
                if (!this.isMouseDown) return false
                this.isMouseDown = false
                if (e.changedTouches[0].pageX === this.originX) return false;
                this.containerActive = false;
                 this.verify()
            },
            verify() {
                const arr = this.trail // drag y move distance
                const average = arr.reduce(sum) / arr.length // average
                const deviations = arr.map(x => x - average) // deviation array
                const stddev = Math.sqrt(deviations.map(square).reduce(sum) / arr.length) // standard deviation
                const left = parseInt(this.block.style.left)
                this.$emit('success',left)

            },
            reset(h) {
                this.containerActive = false;
                this.containerSuccess = false;
                this.containerFail = false;
                this.sliderLeft = 0;
                this.block.style.left = 0;
                this.sliderMaskWidth = 0;
                this.canvasCtx.clearRect(0, 0, this.w, this.h)
                this.blockCtx.clearRect(0, 0, this.w,this.h)
                this.initImg(h)

            }
        }
    }
</script>
<style scoped>
    .slide-verify {
        position: relative;
        width: 310px;
    }

    .slide-verify-block {
        position: absolute;
        left: 0;
        top: 0
    }

    .slide-verify-refresh-icon {
        position: absolute;
        right: 0;
        top: 0;
        width: 34px;
        height: 34px;
        cursor: pointer;
        background: url("../../assets/move/icon_light.png") 0 -437px;
        background-size: 34px 471px
    }

    .slide-verify-slider {
        position: relative;
        text-align: center;
        width: 310px;
        height: 40px;
        line-height: 40px;
        margin-top: 15px;
        background: #f7f9fa;
        color: #45494c;
        border: 1px solid #e4e7eb
    }

    .slide-verify-slider-mask {
        position: absolute;
        left: 0;
        top: 0;
        height: 40px;
        border: 0 solid #1991FA;
        background: #D1E9FE
    }

    .slide-verify-slider-mask-item {
        position: absolute;
        top: 0;
        left: 0;
        width: 40px;
        height: 40px;
        background: #fff;
        box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
        cursor: pointer;
        transition: background .2s linear
    }

    .slide-verify-slider-mask-item:hover {
        background: #1991FA
    }

    .slide-verify-slider-mask-item:hover .slide-verify-slider-mask-item-icon {
        background-position: 0 -13px
    }

    .slide-verify-slider-mask-item-icon {
        position: absolute;
        top: 15px;
        left: 13px;
        width: 14px;
        height: 12px;
        background: url("../../assets/move/icon_light.png") 0 -26px;
        background-size: 34px 471px
    }
    .container-active .slide-verify-slider-mask-item {
        height: 38px;
        top: -1px;
        border: 1px solid #1991FA;
    }

    .container-active .slide-verify-slider-mask {
        height: 38px;
        border-width: 1px;
    }

    .container-success .slide-verify-slider-mask-item {
        height: 38px;
        top: -1px;
        border: 1px solid #52CCBA;
        background-color: #52CCBA !important;
    }

    .container-success .slide-verify-slider-mask {
        height: 38px;
        border: 1px solid #52CCBA;
        background-color: #D2F4EF;
    }

    .container-success .slide-verify-slider-mask-item-icon {
        background-position: 0 0 !important;
    }

    .container-fail .slide-verify-slider-mask-item {
        height: 38px;
        top: -1px;
        border: 1px solid #f57a7a;
        background-color: #f57a7a !important;
    }

    .container-fail .slide-verify-slider-mask {
        height: 38px;
        border: 1px solid #f57a7a;
        background-color: #fce1e1;
    }

    .container-fail .slide-verify-slider-mask-item-icon {
        top: 14px;
        background-position: 0 -82px !important;
    }

    .container-active .slide-verify-slider-text,
    .container-success .slide-verify-slider-text,
    .container-fail .slide-verify-slider-text {
        display: none;
    }
</style>

在登陆中引入:

  import slideverify from '@/components/loginmove/slide-verify.vue'
    <el-dialog
      append-to-body
      :visible.sync="dialogVisible" :show-close="false"
      width="450px">
      <slideverify :l="42"  ref="dialogopen"
                   :r="10"
                   :w="410"
                   :h="200"
                   :block_y="block_y"
                   :imgurl="imgurl"
                   :miniimgurl="miniimgurl"
                   @success="onSuccess"
                   @fail="onFail"
                   @refresh="onRefresh"
                   :slider-text="text"
      ></slideverify>
    </el-dialog>

获取图片验证码:

   getImageVerifyCode: function() {
        var that = this
        loginApi.getImageVerifyCode().then(res => {
          if (!res || res.code != '20000') {
            this.$message({
              showClose: true,
              message: '获取图形验证码失败,请重试',
              type: 'error'
            })
          } else {
            var imgobj = JSON.parse(res.data)
            that.block_y = imgobj.yHeight
            that.imgurl =  'data:image/png;base64,' + imgobj.bigImage
            that.miniimgurl = 'data:image/png;base64,' + imgobj.smallImage
            that.chenckMoveid = imgobj.chenckMoveid
            if (that.$refs.dialogopen) {
              that.$refs.dialogopen.reset(imgobj.yHeight)
            }
          }
        })
      },
     onRefresh() {
        this.imgurl = ''
        this.miniimgurl = ''
        this.getImageVerifyCode()
      },,
      /* 用户密码登陆方法*/
      submitForm(formName,data) {
        var that = this
        const loading = this.$loading({
          lock: true,
          text: '登录中...',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        })
        this.loading = true
        /* 发起请求*/
        let Base64 = require('js-base64').Base64
        const loginFrom = {
          username: Base64.encode(this.ruleForm2.username),
          password: Base64.encode(this.ruleForm2.password),
          x_index: data,
          chenckMoveid: that.chenckMoveid
        }
        this.$store.dispatch('Login', loginFrom).then(res=> {
          loading.close()
          this.isLogined = true
          this.loading = false
          /* 跳转路由*/
          this.$router.push({ path: '/' })
        }).catch(() => {
          loading.close()
          this.loading = false
          if (that.$refs.dialogopen) {
            that.$refs.dialogopen.reset()
          }
        })
      },

注意:由于采用了是前后端分离的方式,考虑到cookie和session比较麻烦,因此每次获取滑块图片的时候生成一个uuid保存到redis里头,作为key进行保存对应的横坐标。

第二步:后台java代码

生成滑块及图片抠图工具类

package com.app.auth.api.util;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.imageio.ImageIO;

import org.springframework.util.Base64Utils;

 

public class VerifyImageUtil {
 
//    private static Logger log = LoggerFactory.getLogger(VerifyImageUtil.class);
    private static int BOLD = 5;
    private static final String IMG_FILE_TYPE = "jpg";
    private static final String TEMP_IMG_FILE_TYPE = "png";
 
    /**
     * 根据模板切图
     * @param templateFile
     * @param targetFile
     * @return
     * @throws Exception
     */
    public static Map<String, Object> pictureTemplatesCut(File templateFile, File targetFile) throws Exception {
        Map<String, Object> pictureMap = new HashMap<>();
        // 模板图
        BufferedImage imageTemplate = ImageIO.read(templateFile);
        int templateWidth = imageTemplate.getWidth();
        int templateHeight = imageTemplate.getHeight();
 
        // 原图
        BufferedImage oriImage = ImageIO.read(targetFile);
        int oriImageWidth = oriImage.getWidth();
        int oriImageHeight = oriImage.getHeight();
 
        //随机生成抠图坐标X,Y
        //X轴距离右端targetWidth  Y轴距离底部targetHeight以上
        Random random = new Random();
        int widthRandom = random.nextInt(oriImageWidth - 2*templateWidth) + templateWidth;
        int heightRandom = random.nextInt(oriImageHeight - templateHeight);
//        log.info("原图大小{} x {},随机生成的坐标 X,Y 为({},{})", oriImageWidth,oriImageHeight,widthRandom,heightRandom);
 
        // 新建一个和模板一样大小的图像,TYPE_4BYTE_ABGR表示具有8位RGBA颜色分量的图像,正常取imageTemplate.getType()
        BufferedImage newImage = new BufferedImage(templateWidth, templateHeight, imageTemplate.getType());
        //得到画笔对象
        Graphics2D graphics = newImage.createGraphics();
        //如果需要生成RGB格式,需要做如下配置,Transparency 设置透明
        newImage = graphics.getDeviceConfiguration().createCompatibleImage(templateWidth, templateHeight, Transparency.TRANSLUCENT);
 
        // 新建的图像根据模板颜色赋值,源图生成遮罩
        cutByTemplate(oriImage,imageTemplate,newImage,widthRandom,heightRandom);
 
        // 设置“抗锯齿”的属性
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphics.setStroke(new BasicStroke(BOLD, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
        graphics.drawImage(newImage, 0, 0, null);
        graphics.dispose();
 
        ByteArrayOutputStream newImageOs = new ByteArrayOutputStream();//新建流。
        ImageIO.write(newImage, TEMP_IMG_FILE_TYPE, newImageOs);//利用ImageIO类提供的write方法,将bi以png图片的数据模式写入流。
        byte[] newImagebyte = newImageOs.toByteArray();
 
        ByteArrayOutputStream oriImagesOs = new ByteArrayOutputStream();//新建流。
        ImageIO.write(oriImage, IMG_FILE_TYPE, oriImagesOs);//利用ImageIO类提供的write方法,将bi以jpg图片的数据模式写入流。
        byte[] oriImageByte = oriImagesOs.toByteArray();
 
        pictureMap.put("smallImage", Base64Utils.encodeToString(newImagebyte));
        pictureMap.put("bigImage", Base64Utils.encodeToString(oriImageByte));
        System.out.println("widthRandom:"+widthRandom);
        pictureMap.put("xWidth",widthRandom);
        pictureMap.put("yHeight",heightRandom);
        return pictureMap;
    }
 
    /**
     * 添加水印
     * @param oriImage
     */
    /*private static BufferedImage addWatermark(BufferedImage oriImage) throws IOException {
        Graphics2D graphics2D = oriImage.createGraphics();
        graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        // 设置水印文字颜色
        graphics2D.setColor(Color.BLUE);
        // 设置水印文字Font
        graphics2D.setFont(new java.awt.Font("宋体", java.awt.Font.BOLD, 50));
        // 设置水印文字透明度
        graphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5f));
        // 第一参数->设置的内容,后面两个参数->文字在图片上的坐标位置(x,y)
        graphics2D.drawString("zhoujin@qq.com", 400,300);
        graphics2D.dispose(); //释放
        return oriImage;
    }*/
 
    /**
     * @param oriImage  原图
     * @param templateImage  模板图
     * @param newImage  新抠出的小图
     * @param x         随机扣取坐标X
     * @param y         随机扣取坐标y
     * @throws Exception
     */
    private static void cutByTemplate(BufferedImage oriImage, BufferedImage templateImage,BufferedImage newImage, int x, int y){
        //临时数组遍历用于高斯模糊存周边像素值
        int[][] martrix = new int[3][3];
        int[] values = new int[9];
 
        int xLength = templateImage.getWidth();
        int yLength = templateImage.getHeight();
        // 模板图像宽度
        for (int i = 0; i < xLength; i++) {
            // 模板图片高度
            for (int j = 0; j < yLength; j++) {
                // 如果模板图像当前像素点不是透明色 copy源文件信息到目标图片中
                int rgb = templateImage.getRGB(i, j);
                if (rgb < 0) {
                    newImage.setRGB(i, j,oriImage.getRGB(x + i, y + j));
 
                    //抠图区域高斯模糊
                    readPixel(oriImage, x + i, y + j, values);
                    fillMatrix(martrix, values);
                    oriImage.setRGB(x + i, y + j, avgMatrix(martrix));
                }
 
                //防止数组越界判断
                if(i == (xLength-1) || j == (yLength-1)){
                    continue;
                }
                int rightRgb = templateImage.getRGB(i + 1, j);
                int downRgb = templateImage.getRGB(i, j + 1);
                //描边处理,,取带像素和无像素的界点,判断该点是不是临界轮廓点,如果是设置该坐标像素是白色
                if((rgb >= 0 && rightRgb < 0) || (rgb < 0 && rightRgb >= 0) || (rgb >= 0 && downRgb < 0) || (rgb < 0 && downRgb >= 0)){
                    newImage.setRGB(i, j, Color.white.getRGB());
                    oriImage.setRGB(x + i, y + j,Color.white.getRGB());
                }
            }
        }
    }
 
    private static void readPixel(BufferedImage img, int x, int y, int[] pixels) {
        int xStart = x - 1;
        int yStart = y - 1;
        int current = 0;
        for (int i = xStart; i < 3 + xStart; i++)
            for (int j = yStart; j < 3 + yStart; j++) {
                int tx = i;
                if (tx < 0) {
                    tx = -tx;
 
                } else if (tx >= img.getWidth()) {
                    tx = x;
                }
                int ty = j;
                if (ty < 0) {
                    ty = -ty;
                } else if (ty >= img.getHeight()) {
                    ty = y;
                }
                pixels[current++] = img.getRGB(tx, ty);
 
            }
    }
 
    private static void fillMatrix(int[][] matrix, int[] values) {
        int filled = 0;
        for (int i = 0; i < matrix.length; i++) {
            int[] x = matrix[i];
            for (int j = 0; j < x.length; j++) {
                x[j] = values[filled++];
            }
        }
    }
 
    private static int avgMatrix(int[][] matrix) {
        int r = 0;
        int g = 0;
        int b = 0;
        for (int i = 0; i < matrix.length; i++) {
            int[] x = matrix[i];
            for (int j = 0; j < x.length; j++) {
                if (j == 1) {
                    continue;
                }
                Color c = new Color(x[j]);
                r += c.getRed();
                g += c.getGreen();
                b += c.getBlue();
            }
        }
        return new Color(r / 8, g / 8, b / 8).getRGB();
    }
}

获取验证码代码:

private static final String IMG_PATH = "/image/picture/*.*";

	private static final String TEMP_IMG_PATH = "/image/temp/temp.png";

	private static final Long IMG_CACHE_EX_TIME = 120L;
	
	/**
	 * 获取图片,由于spring boot打包成jar之后,获取到获取不到resources里头的图片,对此进行处理
	 * @param path
	 * @return 
	 * @author pangxianhe
	 * @date 2020年1月2日
	 */
	public List<File> queryFileList(String path) {

		//获取容器资源解析器
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        List<File> filelist = new ArrayList<File>();
		// 获取远程服务器IP和端口
		try {
			//获取所有匹配的文件
            Resource[] resources = resolver.getResources(path);
            
            for(Resource resource : resources) {
                //获得文件流,因为在jar文件中,不能直接通过文件资源路径拿到文件,但是可以在jar包中拿到文件流
                InputStream stream = resource.getInputStream();
                String targetFilePath =resource.getFilename();
                File ttfFile = new File(targetFilePath);
               /* if(!ttfFile.getParentFile().exists()) {
                	ttfFile.getParentFile().mkdir();
                }*/
                FileUtils.copyInputStreamToFile(stream, ttfFile);
                filelist.add(ttfFile);
            }
		}catch (Exception e) {
			e.printStackTrace();
		}	
		return filelist;
	}

/**
	 * 获取验证码
	 * @return
	 * @throws Exception 
	 * @author pangxianhe
	 * @date 2020年1月2日
	 */
	@RequestMapping(value = "/getImageVerifyCode", method = RequestMethod.POST)
	@ApiOperation(value = "校验ODS账号是否存在", notes = "校验ODS账号是否存在")
	public Result getImageVerifyCode() throws Exception {
		
		// 读取图库目录
		List<File> imgList = queryFileList(IMG_PATH);
		int randNum = new Random().nextInt(imgList.size());
		File targetFile = imgList.get(randNum);
		List<File> tempimgList = queryFileList(TEMP_IMG_PATH);
		File tempImgFile = tempimgList.get(0);
		// 根据模板裁剪图片
		Map<String, Object> resultMap = VerifyImageUtil.pictureTemplatesCut(tempImgFile, targetFile);
		int xWidth = (int) resultMap.get("xWidth");
		// sessionId 为key,value滑动距离X轴,缓存120秒
//		redisTemplate.(session.getId(), xWidth, IMG_CACHE_EX_TIME);
	   String chenckMoveid = IdWorker.get32UUID();
	   BoundValueOperations<String, Object> redisOper = redisTemplate.boundValueOps(chenckMoveid);
	   redisOper.set(xWidth, IMG_CACHE_EX_TIME, TimeUnit.SECONDS);
		// 移除map的滑动距离,不返回给前端
		resultMap.remove("xWidth");
		resultMap.put("chenckMoveid", chenckMoveid);
		return Result.success().put("data",JSONObject.toJSON(resultMap).toString() );
	}

图片保存路径:

登陆验证代码:

// 校验滑块随机数
			if (ObjectUtil.isNull(x_index)||ObjectUtil.isNull(chenckMoveid)) {
				return Result.error("请使用滑块验证码");
			} else {
				// 获取readis缓存的随机数
				Object x_index_orld = redisTemplate.opsForValue().get(String.valueOf(chenckMoveid));
				if (ObjectUtil.isNull(x_index_orld)) {
					return  Result.error("请刷新滑块验证码");
				} else {
					 Double dMoveLength = Double.valueOf(x_index_orld.toString());
					 Double xWidth = Double.valueOf(x_index);
					 if (Math.abs(xWidth - dMoveLength) > 10) {
			                //验证不通过,这个地方需要注意一下,不管他是否验证通过,都需要重置一下图片和坐标位置,避免暴力破解
                            redisTemplate.delete(String.valueOf(chenckMoveid));
							return  Result.error("请拖动到正确的位置");
			            } else {
			               //验证通过
			            	redisTemplate.delete(String.valueOf(chenckMoveid));
			            }
				}
			}

最后一步,见证奇迹的时刻:

有人说缺少result类,已经补上,其实这个可以根据自己的项目进行封装的。

package com.app.base.kernel.model;

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

import cn.hutool.http.HttpStatus;

/**
 * @FileName Result.java
 * @Description: 返回数据
 *
 * 
 * 
 */
public class Result extends HashMap<String, Object> {
	private static final long serialVersionUID = 1L;

	public Result() {
		put("code", 20000);// 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;code为非20000是抛错 可结合自己业务进行修改
		put("message", "success");
	}

	public static Result error() {
		return error(HttpStatus.HTTP_INTERNAL_ERROR, "未知异常,请联系管理员");
	}

	public static Result error(String message) {
		return error(HttpStatus.HTTP_INTERNAL_ERROR, message);
	}

	public static Result error(int code, String message) {
		Result result = new Result();
		result.put("code", code);
		result.put("message", message);
		return result;
	}
	
	public static Result error(int code, String message, Map<String, Object> map) {
		Result result = error(code, message);
		result.putAll(map);
		return result;
	}

	public static Result success(String message) {
		Result result = new Result();
		result.put("message", message);
		return result;
	}

	public static Result success(Map<String, Object> map) {
		Result result = new Result();
		result.putAll(map);
		return result;
	}

	public static Result success() {
		return new Result();
	}

	public Result put(String key, Object value) {
		super.put(key, value);
		return this;
	}
}

Logo

前往低代码交流专区

更多推荐