jfinal针对不同形式请求(ajax和普通请求)获取参数和返回不同形式错误信息

jfinal每个包中写FastJson.getJson().parse(rawData, xxx.class)有些重复,而且有时候如果数据格式转换失败的话,直接返回错误页面。导致ajax请求获取不到json数据。

个人增加了一个助手类,可以getBean,也可以getRawData。也可以先检测是否为json格式数据,根据不同情况调用不同方法。

package com.my.rep.common.assist;

import com.alibaba.fastjson.JSONException;
import com.jfinal.core.Controller;
import com.jfinal.core.Injector;
import com.jfinal.json.FastJson;
import com.my.rep.common.myException.ModelFormatException;

import javax.servlet.http.HttpServletRequest;

/**
 * @date 2019/11/20 - 19:45
 */
public class ControllerAssist extends Controller {
    private static final String EMPTY_STRING = "";
    private static final String EMPTY_OBJECT = "{}";
    private static final String JSON_HEADER = "application/json";
    private static final String CONTENT_TYPE = "Content-Type";

    /**
     * 转换rataData为指定类型对象
     * @param cla 需要转换成的类
     * @param rawData rawData,json类型的请求数据
     * @param throwError 是否抛出异常
     * @return 转换后的对象
     */
    public Object getObject(Class<?> cla, String rawData, Boolean throwError) {
        try {
            Object result = FastJson.getJson().parse(rawData, cla);
            System.out.println(result);
            if (EMPTY_OBJECT.equals(result.toString())) {
                if (throwError) {
                    throw new ModelFormatException();
                } else {
                    return null;
                }
            }
            return result;
        } catch (JSONException err) {
            if (throwError) {
                throw new ModelFormatException();
            } else {
                return null;
            }
        }
    }

    public Object getObject(Class<?> cla, String rawData) {
        return getObject(cla, rawData, true);
    }

    /**
     * 转换application/x-www-form-urlencoded或者multipart/form-data的数据为bean对象
     * @param cla 需要转换为的bean类
     * @param request 本次请求
     * @return 转换后的结果
     */
    public Object getBean(Class<?> cla, HttpServletRequest request) {
        return getBean(cla, request, true);
    }

    public Object getBean(Class<?> cla, HttpServletRequest request, boolean throwError) {
        final Object result = Injector.injectBean(cla, "", request, false);

        if (EMPTY_OBJECT.equals(result.toString())) {
            if (throwError) {
                throw new ModelFormatException();
            } else {
                return null;
            }
        } else {
            return result;
        }
    }
}

其中的错误是自己定义的。如下
其中,所有错误类型继承MyException,方便后续的同一控制,MyException继承RuntimeException
在这里插入图片描述

新建一个类用来控制所有的错误信息

public class MyExceptionTip {
    public static final String UPLOAD = "上传格式有误";
    public static final String MODEL_FORMAT = "数据格式有误";
    public static final String NO_DATA = "没有找到任何有关信息";
}

拿其中一个错误举例子:

public class ModelFormatException extends MyException {
    public ModelFormatException() {
        this(MyExceptionTip.MODEL_FORMAT);
    }

    public ModelFormatException(String message) {
        super(message);
    }
    // ...省略构造方法
}

重点来了
创建一个处理异常的拦截器

public class ModelFormatInterceptor implements Interceptor {
    @Inject
    private MyErrorHandle errorHandle;

    @Override
    public void intercept(Invocation inv) {
        try {
            inv.invoke();
        } catch (MyException e) {
            errorHandle.render(inv, e);
        }
    }
}

上面的异常处理中,重点可以把MyException写为RuntimeException,这样就可以对所有的错误都返回其信息了。(不过没有继承MyExcption的例如NullPointerException返回的错误信息就是默认的getMessage()了,见下面的个人的MyErrorHandle 实现就可知晓了)。

// 方便复用
public class MyErrorHandle {
    @Inject
    private MyConnectKit connectKit;

    public void render(Invocation inv, RuntimeException e) {
        final HttpServletRequest request = inv.getController().getRequest();

        // 如果是ajax请求,返回错误信息,否则抛出错误即可,因为抛出错误后jfinal框架会返回错误页面的。
        if (isAjax(request)) {
            inv.getController().renderJson(MyRet.fail(e.getMessage()));
        } else {
            throw e;
        }
    }

    public void render(Invocation inv, String errorMessage) {
        this.render(inv, new RuntimeException(errorMessage));
    }

    public boolean isAjax(HttpServletRequest request) {
        return "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
    }
}

上述的MyRet只是简单封装了一下Ret

public class MyRet extends Ret {
    public static final String DATA = "data";
    public static final String MESSAGE = "message";

    public MyRet() {
    }

    public static Ret ok(Object object) {
        return ok().set(DATA, object);
    }

    public static Ret fail (String message) {
        return fail().set(MESSAGE, message);
    }
}

最后配置Config中的全局拦截器就好了

	@Override
	public void configInterceptor(Interceptors me) {
		me.addGlobalActionInterceptor(new ModelFormatInterceptor());
	}

个人简单应用举例子

public class UserController extends Controller {
    @Inject
    private UserService service;
    @Inject
    private ControllerAssist controllerAssist;

    private User getUser() {
        return (User) controllerAssist.getObject(User.class, getRawData());
        // 根据需要可以随时切换为
        // return (User) controllerAssist.getBean(User.class, this.getRequest());
        // 也可以改为那个二者检测版本的方法
    }
    
    /**
     * 获得当前用户代言店铺列表
     * @render List<Shop>
     */
    public void getRepShopList() {
        renderJson(service.getRepShopList(getUser()));
    }

    /**
     * 得到用户信息
     * @render Model: User
     */
    public void getInfo() {
        renderJson(service.getInfo(getUser()));
    }
}

觉得还行的话给我的博客点个赞吧,谢谢您。

csdn本篇博客

评论区

流觞w曲水

2019-11-22 20:59

注:因为个人使用jfinal为微信小程序做后台,暂时没有涉及到html错误页面,所以,上述只能实现ajax返回详细的错误信息,而html页面的话,即使是指定的错误,也只能是官方的500错误页面了,后续写后台管理系统时,应该会加上指定类型的错误页面,现在暂时没有实现,到时候实现了分享上来。

JFinal

2019-11-22 21:26

代码简单实用,赞

此外,可以考虑做个 BaseController extends Controller,在其中添加一个 getUser 方法,例如:
public class BaseController extends Controller {
@Inject
private UserService service;
@Inject
private ControllerAssist controllerAssist;

private User getUser() {
return (User) controllerAssist.getObject(User.class, getRawData());
}
}

然后在用的地方只需要继承 BaseController 来使用了

流觞w曲水

2019-11-22 21:43

@JFinal 好的,待会加上,谢谢您的建议。