在JFinal的Controller中接收json数据

本文介绍了如何在JFinal框架中接收和解析JSON格式的数据,包括定义与请求结构相匹配的Java对象,从请求中读取JSON字符串并使用Fastjson进行解析。同时,通过示例代码展示了前端使用AJAX调用的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JFinal中接收URL中的参数或者model中的参数是很方便的,但是对于web2.0的网站来说,经常会以json方式提交比较复杂的数据,比如一个查询,包含了各种过滤条件和排序分页,前端脚本可能提交的数据是这样的:

{
    "type":1,
    "key":"keyword",
    "paging":{
        "size":50,
        "index":0
    },
    "sort":{
        "field":"time",
        "type":"desc"
    }
}


像SpringMVC就提供了@RequestBody将数据绑定到json对象上,但是jFinal不支持,需要自己从POST中读取并解析这个json数据,先定义一个与请求同结构的Java对象,比如起名叫QueryRequest:

packagecom.demo;

import com.demo.Paging;
import com.demo.Sort;

public class QueryRequest {
    private int type;
    private String key;
    private Paging paging;
    private Sort sort;

    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public Paging getPaging() {
        return paging;
    }
    public void setPaging(Paging paging) {
        this.paging = paging;
    }
    public Sort getSort(){
        return sort;
    }
    public void setSort(Sort sort){
        this.sort = sort;
    }
}


其中用到了Paging和Sort两个类:

package com.demo;

public class Paging {
    private int size;
    private int index;
    
    public int getSize() {
        return size;
    }
    public void setSize(int size) {
        this.size = size;
    }
    public int getIndex() {
        return index;
    }
    public void setIndex(int index) {
        this.index = index;
    }
}
package com.demo;

public class Sort {
    private String field;
    private String type;
    
    public String getField() {
        return field;
    }
    public void setField(String field) {
        this.field = field;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
}


然后在Controller里就从request中读取json字符串,然后调用fastjson解析提交的数据了,:

@Before(POST.class)
public void getData(){
    try{
        //从requst中读取json字符串
        StringBuilder json = new StringBuilder(); 
        BufferedReader reader = this.getRequest().getReader();
        String line = null;
        while((line = reader.readLine()) != null){
            json.append(line);
        }
        reader.close();

        //调用fastjson解析出对象
        QueryRequest request = JSONObject.parseObject(json.toString(), QueryRequest.class);
        
        //然后就可以使用request得到请求的所有数据了
        //下略
        //.......
    }
    catch(Exception ex){
        //异常处理,略
    }
    
    renderText("测试");
}


转换部分会经常使用,可以提出来:

/**
 * 取Request中的数据对象
 * @param valueType
 * @return
 * @throws Exception 
 */
protected <T> T getRequestObject(Class<T> valueType) throws Exception {
    StringBuilder json = new StringBuilder();
    BufferedReader reader = this.getRequest().getReader();
    String line = null;
    while((line = reader.readLine()) != null){
        json.append(line);
    }
    reader.close();
    
    return JSONObject.parseObject(json.toString(), valueType);
}


使用的时候一句就行了:

QueryRequest requst = getRequestObject(QueryRequest.class);



另外附上前端ajax调用的脚本:

$.ajax({
    "url": "/home/getDate",      //路径
    "cache": false,              //不缓存
    "async": true,               //异步
    "type": "POST",              //POST方式提交
    "dataType": "json",          //json格式,重要
    "contentType": "application/json",      //json格式
    "data": {},                  //要提交的数据对象
    success: function (json) { //成功处理
    },
    error: function (x, e) {  //异常处理
    }
});


PS:很喜欢jFinal,相比于SpringMVC庞大的体积,jFinal真是的很小巧。

PPS:使用的是jFinal-2.0,配合fastjson-1.2.3,之前用fastjson-1.2.4时会有问题。






<think>好的,用户的问题是关于如何在Spring MVC的拦截器中处理JSON数据并修改HTTP请求体。首先,我需要回忆一下Spring拦截器的相关知识。拦截器是基于HandlerInterceptor接口实现的,可以在请求处理的不同阶段执行逻辑。用户提到的问题主要是如何在拦截器中读取和修改请求体,同时避免流只能读取一次的问题。 记得之前在处理HTTP请求时,特别是使用@RequestBody注解时,请求体是通过输入流读取的,而流一旦被读取,就不能再次读取了。所以如果在拦截器中直接读取了请求体,后续Controller中的@RequestBody就会失败。这个问题需要解决,如何让拦截器读取后,还能让后续的处理正常获取数据。 根据引用[1],用户提到使用拦截器读取数据导致后续无法获取,因为流只能读一次。这里可能需要使用HttpServletRequestWrapper来包装原始的请求,使得可以多次读取请求体。HttpServletRequestWrapper允许我们缓存请求体的内容,这样在拦截器中读取之后,后续的处理仍然可以获取到数据。 步骤大概是这样的:首先,在拦截器的preHandle方法中,将原始的HttpServletRequest替换为自定义的包装类。这个包装类会在第一次读取输入流时,将内容缓存起来,后续的读取操作都从这个缓存中获取,而不是直接从流中读取。这样,无论拦截器还是Controller中的@RequestBody,都能正常获取到请求体的数据。 然后,处理JSON数据。在拦截器中,读取到请求体后,可以将其转换为JSON对象,进行修改或者其他处理。修改完成后,再将修改后的JSON字符串重新写入到请求体中。这里需要注意的是,修改后的数据需要重新设置到包装类的缓存中,并且要更新内容的长度,否则可能会引发错误。 另外,引用[3]提到使用@WebFilter配置过滤器,但这里用户的问题是关于拦截器Interceptor,而不是Filter。拦截器和过滤器虽然类似,但属于不同的机制。拦截器属于Spring MVC的一部分,而过滤器是Servlet规范的一部分。所以解决方案应该基于拦截器,而不是过滤器。 引用[4]提到Spring Boot中的拦截器配置,需要实现HandlerInterceptor接口,并注册到拦截器注册表中。所以用户需要创建一个自定义拦截器,并覆盖preHandle方法,在其中处理请求体的读取和修改。 具体实现步骤可能包括: 1. 创建自定义的HttpServletRequestWrapper,重写getInputStream和getReader方法,允许多次读取请求体。 2. 在拦截器的preHandle方法中,将原始请求替换为自定义的包装请求。 3. 读取请求体内容,解析为JSON对象。 4. 修改JSON数据。 5. 将修改后的JSON数据重新写入包装类的缓存中。 6. 确保后续的Controller可以正确获取修改后的请求体。 需要注意的是,请求体的内容长度可能会因为修改而改变,因此在包装类中需要更新对应的头信息,如Content-Length,否则可能会导致客户端或服务器端处理异常。 此外,可能还需要处理字符编码的问题,确保读取和写入的字符集一致,避免乱码。 最后,要验证解决方案的有效性,编写测试用例,确保拦截器能够正确修改请求体,并且Controller能够接收到修改后的数据。</think>在拦截器中处理JSON请求体需要解决流只能读取一次的问题,可通过自定义`HttpServletRequestWrapper`实现多次读取。以下是具体实现步骤: ### 一、创建可重复读取的Request包装类 ```java public class BodyCachingRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; public BodyCachingRequestWrapper(HttpServletRequest request) throws IOException { super(request); InputStream inputStream = request.getInputStream(); this.body = StreamUtils.copyToByteArray(inputStream); } @Override public ServletInputStream getInputStream() { return new CachedBodyServletInputStream(this.body); } @Override public BufferedReader getReader() { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.body); return new BufferedReader(new InputStreamReader(byteArrayInputStream)); } } // 自定义ServletInputStream实现 class CachedBodyServletInputStream extends ServletInputStream { private final InputStream cachedBodyInputStream; public CachedBodyServletInputStream(byte[] cachedBody) { this.cachedBodyInputStream = new ByteArrayInputStream(cachedBody); } @Override public int read() throws IOException { return cachedBodyInputStream.read(); } @Override public boolean isFinished() { try { return cachedBodyInputStream.available() == 0; } catch (IOException e) { throw new RuntimeException(e); } } @Override public boolean isReady() { return true; } @Override public void setReadListener(ReadListener listener) { throw new UnsupportedOperationException(); } } ``` ### 二、实现拦截器逻辑 ```java public class JsonInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { BodyCachingRequestWrapper wrappedRequest = new BodyCachingRequestWrapper(request); // 1. 获取JSON数据 String bodyStr = new String(wrappedRequest.getBody(), request.getCharacterEncoding()); JSONObject json = JSON.parseObject(bodyStr); // 2. 修改JSON内容 json.put("modifiedTime", LocalDateTime.now()); // 3. 重新写入请求体 wrappedRequest.setBody(json.toJSONString().getBytes()); // 替换原始Request对象 request = wrappedRequest; return true; } } ``` ### 三、注册拦截器 ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new JsonInterceptor()) .addPathPatterns("/api/**"); } } ``` ### 关键点说明 1. **流复用原理**:通过缓存请求体字节数组实现多次读取[^1] 2. **JSON处理**:使用Fastjson/Alibaba JSON等工具解析修改数据 3. **字符编码**:必须使用`request.getCharacterEncoding()`保持一致 4. **内容长度**:修改后需要重置`Content-Length`头信息 ### 注意事项 1. 拦截器路径需精确匹配需要处理JSON的接口 2. 修改后的JSON字段类型需与接收对象匹配 3. 大文件请求需要考虑内存优化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值