Handler里怎么获取Controller 执行 getFileS()方法

目前公共参数拦截校验,因涉及请求参数修改中继,由Interceptor变更为Handler来处理。

现需要在Handler获取带上传的target,用来执行getFiles()确保文件上传以及参数的正确获取。


评论区

杜福忠

2022-06-29 18:38

试试这样写
String contentType = request.getContentType();
if( contentType != null && contentType.toLowerCase().contains("multipart/form-data")){
if (request instanceof MultipartRequest == false)
request = new MultipartRequest(request);
List files = ((MultipartRequest)request).getFiles();
}
next.handle(target, request, response, isHandled);

JFinal

2022-06-29 20:26

@杜福忠 这个方案非常好,赞

azzcsimp

2022-06-30 11:00

感谢两位大佬,已经实现目标需求,之前因为搞了个注解配置在Controller上用来标注请求类型,一直搞错方向在纠结如何获取Controller了。

azzcsimp

2022-06-30 14:13

@杜福忠 又尴尬了,此问题是延续上次参数注入问题(https://jfinal.com/feedback/8299),之前没有考虑到文件上传,现在一旦先new MultipartRequest,导致后面request内的请求参数无法修改。继承MultipartRequest自定义实现,内部的multipartRequest为私有对象,无法获取。完全重写MultipartRequest方法,又导致baseUploadPath,maxPostSize,encoding需要手动自定的问题

azzcsimp

2022-06-30 14:18

@杜福忠 整体请求逻辑如下
1.接收前端发起请求(文件未加密,参数加密)
2.handler内获取request,并执行getFiles()方法,保障后续请求参数获取
3.对加密数据进行解密,并对请求参数进行明文化新增或修改
4.请求参数中继至Validator、Controller

杜福忠

2022-06-30 14:32

第一层 使用 MultipartRequest 做文件格式协议解析,然后再 EpRequestWrapper 做第二次参数值解密就可以了,两个Handler各做各的事情,有什么影响吗?
EpRequestWrapper 里面拿不到值了?
加密一般只加密 值,不加密键啊,所以获取到的值应该只是密文,解密后放入 EpRequestWrapper 里面自建的map对象,后面Request的get系列都走的是map的get就可以了,不知道你那怎么写的了

azzcsimp

2022-06-30 14:36

@杜福忠 这边的加密是所有请求参数的json数据整体加密。请求公共参数有3个,业务参数随机,解密后把业务参数重新按照键值封装进request进行中继。如果前面new MultipartRequest()后,后面再进行new EpRequestWrapper()进行参数值修改,一直报Corrupt form data: premature ending异常。

杜福忠

2022-06-30 14:53

@azzcsimp multipart/form-data HTTP格式里面请求数据是用分隔符分隔的,又不是JSON格式的,所以你那个EpRequestWrapper里面需要支持application/json的同时也要支持multipart/form-data 格式

azzcsimp

2022-06-30 16:46

@杜福忠 已处理成功,采用的方式是新建同名com.jfinal.upload.MultipartRequest类替代JFinal原生类,具体改动如下
1.新增params变量
public Map params = new HashMap<>();

2.构造方法 增加initParam()调用,用来初始化自定义参数
public MultipartRequest(HttpServletRequest request, String uploadPath, long maxPostSize, String encoding) {
super(request);
wrapMultipartRequest(request, getFinalPath(uploadPath), maxPostSize, encoding);
initParam();
}

public MultipartRequest(HttpServletRequest request, String uploadPath, long maxPostSize) {
super(request);
wrapMultipartRequest(request, getFinalPath(uploadPath), maxPostSize, encoding);
initParam();
}

public MultipartRequest(HttpServletRequest request, String uploadPath) {
super(request);
wrapMultipartRequest(request, getFinalPath(uploadPath), maxPostSize, encoding);
initParam();
}

public MultipartRequest(HttpServletRequest request) {
super(request);
wrapMultipartRequest(request, baseUploadPath, maxPostSize, encoding);
initParam();
}


private void initParam(){
Map map = new HashMap();
Enumeration enumm = multipartRequest.getParameterNames();
while (enumm.hasMoreElements()) {
String name = (String) enumm.nextElement();
map.put(name, multipartRequest.getParameterValues(name));
}
this.params.putAll(map);
}

3.增加参数变动方法,addParameter、removeParameter
4.重写getParameterNames、getParameter、getParameterValues、getParameterMap方法

azzcsimp

2022-06-30 16:48

常规请求,可以重新new无数次EpRequestWrapper,进行requeset封装,
MultipartRequest 因自身构造函数实现,只能new一次,否则报Corrupt form data: premature ending异常。

azzcsimp

2022-06-30 16:50

@JFinal 后续版本是否可以为MultipartRequest扩展此功能。主要解决一次请求中途参数二次修改的使用场景。

lyh061619

2022-07-01 01:07

看上面你的问题描述,业务要求是对请求过来参数(json)做密数处理了,现在你的想法是将这些已加密参数做个统一解密处理,然后在validate、controller中直接使用,这个问题通过重写JsonRequest(这个类已经接管request) 如:MyJsonRequest 然后如下:

一、重写这处理json数据
public JsonRequest(String jsonString, HttpServletRequest req) {
Object json = com.alibaba.fastjson.JSON.parse(jsonString);
if (json instanceof com.alibaba.fastjson.JSONObject) {
jsonObject = (com.alibaba.fastjson.JSONObject)json;
} else if (json instanceof com.alibaba.fastjson.JSONArray) {
jsonArray = (com.alibaba.fastjson.JSONArray)json;
}

this.req = req;
}

二、重写这处理getPara(xx)数据
@Override
public String getParameter(String name) {
// String[] ret = getParaMap().get(name);
// return ret != null && ret.length != 0 ? ret[0] : null;

// 优化性能,避免调用 getParaMap() 触发调用 createParaMap(),从而大概率避免对整个 jsonObject 进行转换
if (jsonObject != null && jsonObject.containsKey(name)) {
Object value = jsonObject.get(name);
if (value instanceof com.alibaba.fastjson.JSON) {
return ((com.alibaba.fastjson.JSON)value).toJSONString();
} else if (value != null) {
return value.toString();
} else {
// 需要考虑是否返回 "",表单提交请求只要 name 存在则值不会为 null
return null;
}
} else {
return req.getParameter(name);//这个位置处理解密数据
}
}
三、在constants配置
me.setJsonRequestFactory((json, req)->{
return new MyJsonRequest(json, req);
});
这解决方案不行么?为何搞得如此复杂。

azzcsimp

2022-07-01 11:40

@lyh061619
上文提到的EpRequestWrapper,就是类似MyJsonRequest 的实现。非文件上传类的请求,按此已经实现了需求。这里主要是兼容multipart/form-data请求,需要前置执行getFiles()方法获取文件后,便与后续其它参数的正常获取。

azzcsimp

2022-07-01 11:56

@lyh061619
[常规请求]:
获取request->获取加密参数->参数解密装载进request->next.handle(target, request, response, isHandled)->validate->controller。

[multipart/form-data请求]:
获取MultipartRequest->getFiles()->获取加密参数->参数解密装载进request->next.handle(target, request, response, isHandled)->validate->controller。

问题就在于MultipartRequest不能像JsonRequest那样可劲new。而且原生的MultipartRequest嵌入在其它代码类,重新继承MultipartRequest,不知道有没有类似setJsonRequestFactory的方法来接管。

杜福忠

2022-07-01 15:15

@azzcsimp 明白你的意思了,项目如果是Tomcat运行,是class运行,上面写是没有问题,优先加载的 WEB-INF/classes文件。 如果是jfinal-undertow运行的话,最后项目class也会被打为jar,加载的时候就会报错。 推荐自建一个 BaseController 里面覆写 getFiles 系列方法,new 自建的类就可以了,文件上传前面就不再拦截了

热门反馈

扫码入社