MyBatis Update with Subqueries, Batch Insert of List Attributes, and a Spring Filter for Logging Request and Response Data

This article demonstrates how to use MyBatis to update records with sub‑queries, batch‑insert list‑type attributes, defines the related Java bean, and implements a Spring servlet filter (with request and response wrappers) to log request parameters and response results.

FunTester
FunTester
FunTester
MyBatis Update with Subqueries, Batch Insert of List Attributes, and a Spring Filter for Logging Request and Response Data

The author first describes two common MyBatis features: (1) updating a record while reading data from another table using sub‑queries (an inner join would be better but cannot be used because the update involves the apiId field), and (2) batch inserting a list attribute.

Update with sub‑queries

<update id="updateCase" parameterType="com.okay.family.common.bean.testcase.request.CaseAttributeBean">
    UPDATE
    <include refid="table"/>
    c
    SET
    editor=#{uid},name=#{name},envId=#{envId},serviceId=#{serviceId},moduleId=#{moduleId},projectList=#{projectList,jdbcType=OTHER,typeHandler=com.okay.family.common.typehandler.ListIntegerHandler},apiId=#{apiId},
    headermoco=(SELECT header_para FROM family_server_api_info WHERE id = #{apiId}),
    paramsmoco=(SELECT request_par FROM family_server_api_info WHERE id = #{apiId})
    WHERE id = #{id}
</update>

Batch insert of a list attribute

<insert id="addCaseProjectRelation" parameterType="com.okay.family.common.bean.testcase.request.CaseAttributeBean">
    insert into
    <include refid="case_project_relation"/>
    (caseId,projectId)
    values
    <foreach collection="projectList" item="projectId" index="index" separator=",">
        (#{id}, #{projectId})
    </foreach>
</insert>

The related Java bean CaseAttributeBean is shown below:

class CaseAttributeBean extends AbstractBean {
    private static final long serialVersionUID = -629232822729332L;
    int id;
    int uid;
    int envId;
    /** 关联服务id */
    int serviceId;
    /** 关联服务模块id */
    int moduleId;
    @NotNull
    String name;
    List<Integer> projectList;
    int apiId;
    @NotNull
    @Pattern(regexp = "add|update|copy", message = "类型错误,应该传:add|update|copy")
    String type;
}

Next, the article introduces a servlet filter named WrappingFilter that logs the request URL, execution time, request parameters (or body), and the response content. The filter wraps the original request and response with RequestWrapper and ResponseWrapper to allow the body to be read multiple times.

package com.okay.family.common.wapper;

import com.okay.family.fun.utils.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.invoke.MethodHandles;

@Component
@WebFilter(urlPatterns = "/*", filterName = "wrappingFilter")
public class WrappingFilter implements Filter {
    private static Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
    public void init(FilterConfig config) throws ServletException {}
    public void destroy() {}
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        ResponseWrapper responseWrapper = new ResponseWrapper(resp);
        RequestWrapper requestWrapper = new RequestWrapper(req);
        String url = requestWrapper.getRequestURL().toString();
        String queryArgs = requestWrapper.getQueryString();
        queryArgs = queryArgs == null ? requestWrapper.getBody() : queryArgs;
        long start = Time.getTimeStamp();
        chain.doFilter(requestWrapper == null ? request : requestWrapper, responseWrapper);
        long end = Time.getTimeStamp();
        byte[] bytes = responseWrapper.getContent();
        String respContent = new String(bytes);
        logger.info("请求:{},耗时:{}ms,参数:{},响应:{}", url, end - start, queryArgs, respContent);
        response.getOutputStream().write(respContent.getBytes());
    }
}

A key point highlighted is that both request and response streams can be read only once, so the wrappers store the data and provide it again for downstream processing.

RequestWrapper (simplified):

public class RequestWrapper extends HttpServletRequestWrapper {
    private final String body;
    public RequestWrapper(HttpServletRequest request) {
        super(request);
        StringBuilder sb = new StringBuilder();
        try (BufferedReader br = request.getReader()) {
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) { }
        body = sb.toString();
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes());
        return new ServletInputStream() {
            public boolean isFinished() { return false; }
            public boolean isReady() { return false; }
            public void setReadListener(ReadListener listener) {}
            public int read() throws IOException { return bais.read(); }
        };
    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }
    public String getBody() { return this.body; }
}

ResponseWrapper (simplified):

public class ResponseWrapper extends HttpServletResponseWrapper {
    private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    private PrintWriter printWriter = new PrintWriter(outputStream);
    public ResponseWrapper(HttpServletResponse response) { super(response); }
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return new ServletOutputStream() {
            public boolean isReady() { return false; }
            public void setWriteListener(WriteListener listener) {}
            public void write(int b) throws IOException { outputStream.write(b); }
            public void write(byte[] b) throws IOException { outputStream.write(b); }
            public void write(byte[] b, int off, int len) throws IOException { outputStream.write(b, off, len); }
            public void flush() throws IOException { outputStream.flush(); }
        };
    }
    @Override
    public PrintWriter getWriter() throws IOException { return printWriter; }
    public void flush() {
        try { printWriter.flush(); printWriter.close(); outputStream.flush(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); }
    }
    public byte[] getContent() { flush(); return outputStream.toByteArray(); }
}

Finally, the author adds a disclaimer that the article is originally published on the “FunTester” public account and should not be reproduced without permission.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavasqlspringloggingMyBatisServlet Filter
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.