Servlet ফিল্টার সহ অনুরোধ পরামিতি পরিবর্তন করুন


114

টমকাট ৪.১ এ একটি বিদ্যমান ওয়েব অ্যাপ্লিকেশন চলছে। একটি পৃষ্ঠাতে একটি এক্সএসএস সমস্যা আছে, তবে আমি উত্সটি সংশোধন করতে পারি না। পৃষ্ঠাটি দেখার আগে আমি প্যারামিটারটি স্যানিটাইজ করার জন্য একটি সার্লেট ফিল্টার লেখার সিদ্ধান্ত নিয়েছি।

আমি এর মতো একটি ফিল্টার ক্লাস লিখতে চাই:

import java.io.*;
import javax.servlet.*;

public final class XssFilter implements Filter {

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException
  {
    String badValue = request.getParameter("dangerousParamName");
    String goodValue = sanitize(badValue);
    request.setParameter("dangerousParamName", goodValue);
    chain.doFilter(request, response);
  }

  public void destroy() {
  }

  public void init(FilterConfig filterConfig) {
  }
}

কিন্তু ServletRequest.setParameterঅস্তিত্ব নেই।

অনুরোধটিকে শৃঙ্খলে নামার আগে আমি কীভাবে অনুরোধের প্যারামিটারটির মান পরিবর্তন করতে পারি?


এইচটিটিএস সার্লেটরেকুয়েটওয়্যার্পারের প্রচুর এপিআই সংজ্ঞায়িত হয়েছে Iআমি প্রতিটি এপিআইটি অর্থবহভাবে বোঝার চেষ্টা করছি av জাভাদোক 'ইউজারিনরোল', 'গেটপ্রিপ্টিনাল'একটিএস এর মতো এপিআই বুঝতে সাহায্য করছে না, ঠিক কোথায় আমি কিছুটা সহায়তা পেতে পারি?
এসকিউমার 86

উত্তর:


132

আপনি যেমন উল্লেখ করেছেন HttpServletRequestতেমন কোনও সেটপ্যারামিটার পদ্ধতি নেই। এটি ইচ্ছাকৃত, যেহেতু ক্লাসটি ক্লায়েন্টের কাছ থেকে এসেছে সেই অনুরোধটিকে প্রতিনিধিত্ব করে, এবং পরামিতিটি সংশোধন করা তার প্রতিনিধিত্ব করবে না।

একটি সমাধান হ'ল HttpServletRequestWrapperক্লাসটি ব্যবহার করা , যা আপনাকে অন্যের সাথে একটি অনুরোধ গুটিয়ে রাখতে দেয়। আপনি এটি সাবক্লাস করতে পারেন এবং getParameterআপনার স্যানিটাইজড মানটি ফেরত দেওয়ার পদ্ধতিটিকে ওভাররাইড করতে পারেন। তারপরে আপনি chain.doFilterমূল অনুরোধের পরিবর্তে সেই মোড়ানো অনুরোধটি পাস করতে পারেন ।

এটি কিছুটা কুরুচিপূর্ণ তবে সার্ভলেট এপিআই বলে যা আপনার করা উচিত। আপনি যদি অন্য কিছুতে doFilterপ্রস্থান করার চেষ্টা করেন , কিছু সার্লেট পাত্রে অভিযোগ করবে যে আপনি অনুমানটি লঙ্ঘন করেছেন, এবং এটি পরিচালনা করতে অস্বীকার করবেন।

আরও মার্জিত সমাধান হ'ল আরও কাজ - প্যারামিটারটি প্রক্রিয়াকরণ করে এমন মূল সার্লেট / জেএসপি সংশোধন করুন, যাতে এটি প্যারামিটারের পরিবর্তে একটি অনুরোধ বৈশিষ্ট্যটি প্রত্যাশা করে । ফিল্টারটি প্যারামিটার পরীক্ষা করে, এটি স্যানিটাইজ করে এবং request.setAttributeস্যানিটাইজড মান সহ বৈশিষ্ট্য (ব্যবহার করে ) সেট করে । কোনও সাবক্ল্যাসিং, কোনও স্পোফিং নয়, তবে আপনার অ্যাপ্লিকেশনের অন্যান্য অংশগুলি পরিবর্তন করতে হবে।


6
এইচটিপিএস সার্লেটেরউইকুয়েস্টআপনার দুর্দান্ত; আমি জানতাম না যে এর অস্তিত্ব আছে। ধন্যবাদ!
জেরেমি স্টেইন

3
অ্যাট্রিবিউট সেটিং বিকল্পের জন্য ধন্যবাদ! শিরোনাম প্রথম সার্লেটস এবং জেএসপিগুলিতে অনুরোধ এবং প্রতিক্রিয়া মোড়ক ব্যবহার করে স্যাম্পেল কোড দেখেছি এবং বিশ্বাস করতে পারছিল না যে অনুমানগুলি লোককে সেই পথে চলতে ঠেলা দেয়।
কেভিন

আমি কন্ট্রোলারে আমার মানগুলি পৌঁছে দিয়েছিলাম এবং আমি থাই প্যারামিটার (ইমেল এবং পাস) সেট করেছি ... এখন আমি কীভাবে আমার <property name="username" value="somemail@gmail.com" /> //Change email on logging in <property name="password" value="*********" />//Change Password on logging in
সার্লেলে

73

রেকর্ডের জন্য, এখানে লেখাটি শেষ করা ক্লাসটি এখানে:

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public final class XssFilter implements Filter {

    static class FilteredRequest extends HttpServletRequestWrapper {

        /* These are the characters allowed by the Javascript validation */
        static String allowedChars = "+-0123456789#*";

        public FilteredRequest(ServletRequest request) {
            super((HttpServletRequest)request);
        }

        public String sanitize(String input) {
            String result = "";
            for (int i = 0; i < input.length(); i++) {
                if (allowedChars.indexOf(input.charAt(i)) >= 0) {
                    result += input.charAt(i);
                }
            }
            return result;
        }

        public String getParameter(String paramName) {
            String value = super.getParameter(paramName);
            if ("dangerousParamName".equals(paramName)) {
                value = sanitize(value);
            }
            return value;
        }

        public String[] getParameterValues(String paramName) {
            String values[] = super.getParameterValues(paramName);
            if ("dangerousParamName".equals(paramName)) {
                for (int index = 0; index < values.length; index++) {
                    values[index] = sanitize(values[index]);
                }
            }
            return values;
        }
    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        chain.doFilter(new FilteredRequest(request), response);
    }

    public void destroy() {
    }

    public void init(FilterConfig filterConfig) {
    }
}

5
আপনাকে getParameterMap পদ্ধতিতে অ্যাকাউন্ট করতে হবে। সম্ভবত নিক্ষেপ এবং অসমর্থিত ব্যতিক্রম যাতে কোনও উপাদান পদ্ধতি ব্যবহার না করে এবং স্যানিটাইজ যুক্তি এড়িয়ে যায়।
টম

1
ভাল কথা, টম। এই বিশেষ ক্ষেত্রে, আমি পরীক্ষা করে দেখেছি এটি কল করা হচ্ছে না, তবে আমার এটি সম্পূর্ণ এবং পরবর্তী ব্যক্তির জন্য যোগ করা উচিত ছিল। ধন্যবাদ!
জেরেমি স্টেইন

13
দেখে মনে হচ্ছে আমি পরের ব্যক্তি জেরেমি। বাহ্যিক অ্যাপ্লিকেশন থেকে তৃতীয় পক্ষের সার্লেলে পাস করা ডেটা সংশোধন করার বিকল্পগুলির সন্ধান করার সময় আমি এই পোস্টটি পেয়েছি। আমার ক্ষেত্রে, সার্লেটটি অনুরোধের ডেটা পেতে HTTPServletRequest.getParameter (), getParameterMap (), এমনকি getAttribute () কল করছে না, সুতরাং, পরীক্ষার এবং ত্রুটির মাধ্যমে, আমি নির্ধারণ করেছি যে সার্লেটটি HTTPServletRequest.getInputStream () কল করছে এবং getQueryString ()। বদ্ধ সার্লেটগুলির জন্য এই কাজটি করার চেষ্টা করা প্রত্যেককে আমার পরামর্শটি হ'ল সত্যিকারের কী চলছে তা বুঝতে HTTPServletRequest এ প্রতিটি একসেসরকে আবৃত করা
ফ্রেড সোবোটকা

3
SrpingMVC- এর জন্য, আপনাকে বসন্তকে বোকা বানানোর জন্য getParameterValues ​​() কে ওভাররাইড করতে হবে। অনুরোধপ্যারমথোডআর্গমেন্টমেন্টসেসলভার.রেসোভেলনেম () সেই পদ্ধতিটি ব্যবহার করে, তাই আপনি ওভাররাইড না করেই মিসিং সার্ভেলেটেক্সেমপ্যারামিটার এক্সেকশন পাবেন। স্প্রিং-বুট ৪.১..7 সহ স্প্রিং বুট 1.2.2 এ পরীক্ষিত।
ব্যারিকু

10

একটি সাধারণ ক্লাস লিখুন যা ইনপুটটির HttpServletRequestWrapperস্যানিটাইজড সংস্করণটি ফেরত দেয় এমন getParameter () পদ্ধতিতে উপশম করে। তারপর আপনার একটি দৃষ্টান্ত পাস HttpServletRequestWrapperকরার Filter.doChain()সরাসরি অনুরোধ বস্তুর পরিবর্তে।


1

আমারও একই সমস্যা ছিল (ফিল্টারে এইচটিটিপি অনুরোধ থেকে একটি পরামিতি পরিবর্তন করা)। আমি একটি ব্যবহার করে শেষ ThreadLocal<String>। ইন Filterআমার আছে:

class MyFilter extends Filter {
    public static final ThreadLocal<String> THREAD_VARIABLE = new ThreadLocal<>();
    public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
        THREAD_VARIABLE.set("myVariableValue");
        chain.doFilter(request, response);
    }
}

আমার অনুরোধ প্রসেসরে ( HttpServlet, জেএসএফ নিয়ন্ত্রক বা অন্য কোনও এইচটিটিপি অনুরোধ প্রসেসর), আমি বর্তমান থ্রেডের মানটি ফিরে পেয়েছি:

...
String myVariable = MyFilter.THREAD_VARIABLE.get();
...

সুবিধাদি:

  • HTTP পরামিতিগুলি পাস করার চেয়ে বহুমুখী (আপনি POJO অবজেক্টগুলি পাস করতে পারেন)
  • সামান্য দ্রুত (ভেরিয়েবল মানটি বের করার জন্য ইউআরএল বিশ্লেষণ করার প্রয়োজন নেই)
  • আরো মার্জিত HttpServletRequestWrapperবয়লারপ্লেট thant
  • ভেরিয়েবল স্কোপটি কেবল এইচটিটিপি অনুরোধের চেয়েও বিস্তৃত (যখন করার সময় আপনার যে সুযোগ রয়েছে তা request.setAttribute(String,Object)অর্থাত্ আপনি অন্যান্য ফিল্টারারগুলিতে ভেরিয়েবলটি অ্যাক্সেস করতে পারেন।

অসুবিধা:

  • আপনি এই পদ্ধতিটি কেবল তখনই ব্যবহার করতে পারবেন যখন ফিল্টারটি প্রক্রিয়াকৃত থ্রেডটি এইচটিটিপি অনুরোধের প্রক্রিয়াজাতকরণের মতো হয় (আমি জানি সমস্ত জাভা-ভিত্তিক সার্ভারে এটিই ঘটবে)। ফলস্বরূপ, যখন এটি কাজ করবে না
    • এইচটিটিপি পুনঃনির্দেশ করা (কারণ ব্রাউজারটি একটি নতুন এইচটিটিপি অনুরোধ করে এবং গ্যারান্টি দেওয়ার কোনও উপায় নেই যে এটি একই থ্রেড দ্বারা প্রক্রিয়া করা হবে)
    • প্রক্রিয়াকরণের পৃথক থ্রেড ডাটা যখন ব্যবহার করে, যেমন java.util.stream.Stream.parallel, java.util.concurrent.Future, java.lang.Thread
  • আপনাকে অবশ্যই অনুরোধ প্রসেসর / অ্যাপ্লিকেশনটি সংশোধন করতে সক্ষম হতে হবে

কিছু পক্ষের নোট:

  • এইচটিটিপি অনুরোধগুলি প্রক্রিয়া করার জন্য সার্ভারের একটি থ্রেড পুল রয়েছে। যেহেতু এটি পুল:

    1. এই থ্রেড পুলের একটি থ্রেড অনেকগুলি এইচটিটিপি অনুরোধগুলিতে প্রক্রিয়া করবে, তবে একবারে কেবলমাত্র একটি (যাতে আপনার ব্যবহারের পরে আপনার পরিবর্তনশীল পরিষ্কার করতে হবে বা প্রতিটি এইচটিটিপি অনুরোধের জন্য এটি সংজ্ঞায়িত করতে হবে) কোডের দিকে মনোযোগ দিন যেমন if (value!=null) { THREAD_VARIABLE.set(value);}আপনি মানটি পুনরায় ব্যবহার করবেন পূর্ববর্তী এইচটিটিপি অনুরোধটি যখন valueবাতিল হয়: পার্শ্ব প্রতিক্রিয়াগুলি নিশ্চিত হয়)।
    2. দুটি অনুরোধ একই থ্রেড দ্বারা প্রক্রিয়া করা হবে এমন কোন গ্যারান্টি নেই (এটি হতে পারে তবে আপনার কোনও গ্যারান্টি নেই)। আপনার যদি এক অনুরোধ থেকে অন্য অনুরোধের জন্য ব্যবহারকারীর ডেটা রাখতে হয় তবে এটি ব্যবহার করা ভালHttpSession.setAttribute()
  • জেইই @RequestScopedঅভ্যন্তরীণভাবে একটি ThreadLocalব্যবহার করে ThreadLocalতবে ব্যবহারটি আরও বহুমুখী: আপনি এটি নন জেইই / সিডিআই পাত্রে ব্যবহার করতে পারেন (যেমন মাল্টিথ্রেডেড জেআরই অ্যাপ্লিকেশনগুলিতে)

থ্রেডের সুযোগে একটি পরামিতি সেট করা কি আসলেই ভাল ধারণা? একাধিক অনুরোধগুলি কি একই থ্রেডটি দেখতে পাবে? (আমি ধরে নিই না)
জ্যাচারি ক্রেগ

এটি কি একটি ভাল ধারণা = হ্যাঁ (তবে আপনি কী করছেন তা আপনার জানতে হবে, যাইহোক জেইই @RequestScopedঅভ্যন্তরীণভাবে একই কাজ করে)। একাধিক অনুরোধ একই থ্রেডটি দেখতে পাবে = না (বা কমপক্ষে আপনার কোনও গ্যারান্টি নেই)। আমি এই পয়েন্টগুলি সুনির্দিষ্টভাবে উত্তর সম্পাদনা করেছি।
জুলিয়েন ক্রোনেগ

1

এটাই আমি শেষ করেছিলাম

//import ../../Constants;

public class RequestFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(RequestFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
        throws IOException, ServletException {
        try {
            CustomHttpServletRequest customHttpServletRequest = new CustomHttpServletRequest((HttpServletRequest) servletRequest);
            filterChain.doFilter(customHttpServletRequest, servletResponse);
        } finally {
            //do something here
        }
    }



    @Override
    public void destroy() {

    }

     public static Map<String, String[]> ADMIN_QUERY_PARAMS = new HashMap<String, String[]>() {
        {
            put("diagnostics", new String[]{"false"});
            put("skipCache", new String[]{"false"});
        }
    };

    /*
        This is a custom wrapper over the `HttpServletRequestWrapper` which 
        overrides the various header getter methods and query param getter methods.
        Changes to the request pojo are
        => A custom header is added whose value is a unique id
        => Admin query params are set to default values in the url
    */
    private class CustomHttpServletRequest extends HttpServletRequestWrapper {
        public CustomHttpServletRequest(HttpServletRequest request) {
            super(request);
            //create custom id (to be returned) when the value for a
            //particular header is asked for
            internalRequestId = RandomStringUtils.random(10, true, true) + "-local";
        }

        public String getHeader(String name) {
            String value = super.getHeader(name);
            if(Strings.isNullOrEmpty(value) && isRequestIdHeaderName(name)) {
                value = internalRequestId;
            }
            return value;
        }

        private boolean isRequestIdHeaderName(String name) {
            return Constants.RID_HEADER.equalsIgnoreCase(name) || Constants.X_REQUEST_ID_HEADER.equalsIgnoreCase(name);
        }

        public Enumeration<String> getHeaders(String name) {
            List<String> values = Collections.list(super.getHeaders(name));
            if(values.size()==0 && isRequestIdHeaderName(name)) {
                values.add(internalRequestId);
            }
            return Collections.enumeration(values);
        }

        public Enumeration<String> getHeaderNames() {
            List<String> names = Collections.list(super.getHeaderNames());
            names.add(Constants.RID_HEADER);
            names.add(Constants.X_REQUEST_ID_HEADER);
            return Collections.enumeration(names);
        }

        public String getParameter(String name) {
            if (ADMIN_QUERY_PARAMS.get(name) != null) {
                return ADMIN_QUERY_PARAMS.get(name)[0];
            }
            return super.getParameter(name);
        }

        public Map<String, String[]> getParameterMap() {
            Map<String, String[]> paramsMap = new HashMap<>(super.getParameterMap());
            for (String paramName : ADMIN_QUERY_PARAMS.keySet()) {
                if (paramsMap.get(paramName) != null) {
                    paramsMap.put(paramName, ADMIN_QUERY_PARAMS.get(paramName));
                }
            }
            return paramsMap;
        }

        public String[] getParameterValues(String name) {
            if (ADMIN_QUERY_PARAMS.get(name) != null) {
                return ADMIN_QUERY_PARAMS.get(name);
            }
            return super.getParameterValues(name);
        }

        public String getQueryString() {
            Map<String, String[]> map = getParameterMap();
            StringBuilder builder = new StringBuilder();
            for (String param: map.keySet()) {
                for (String value: map.get(param)) {
                    builder.append(param).append("=").append(value).append("&");
                }
            }
            builder.deleteCharAt(builder.length() - 1);
            return builder.toString();
        }
    }
}

1

আপনার সমস্ত মন্তব্যের ভিত্তিতে এখানে আমার প্রস্তাব যা আমার পক্ষে কাজ করেছে:

 private final class CustomHttpServletRequest extends HttpServletRequestWrapper {

    private final Map<String, String[]> queryParameterMap;
    private final Charset requestEncoding;

    public CustomHttpServletRequest(HttpServletRequest request) {
        super(request);
        queryParameterMap = getCommonQueryParamFromLegacy(request.getParameterMap());

        String encoding = request.getCharacterEncoding();
        requestEncoding = (encoding != null ? Charset.forName(encoding) : StandardCharsets.UTF_8);
    }

    private final Map<String, String[]> getCommonQueryParamFromLegacy(Map<String, String[]> paramMap) {
        Objects.requireNonNull(paramMap);

        Map<String, String[]> commonQueryParamMap = new LinkedHashMap<>(paramMap);

        commonQueryParamMap.put(CommonQueryParams.PATIENT_ID, new String[] { paramMap.get(LEGACY_PARAM_PATIENT_ID)[0] });
        commonQueryParamMap.put(CommonQueryParams.PATIENT_BIRTHDATE, new String[] { paramMap.get(LEGACY_PARAM_PATIENT_BIRTHDATE)[0] });
        commonQueryParamMap.put(CommonQueryParams.KEYWORDS, new String[] { paramMap.get(LEGACY_PARAM_STUDYTYPE)[0] });

        String lowerDateTime = null;
        String upperDateTime = null;

        try {
            String studyDateTime = new SimpleDateFormat("yyyy-MM-dd").format(new SimpleDateFormat("dd-MM-yyyy").parse(paramMap.get(LEGACY_PARAM_STUDY_DATE_TIME)[0]));

            lowerDateTime = studyDateTime + "T23:59:59";
            upperDateTime = studyDateTime + "T00:00:00";

        } catch (ParseException e) {
            LOGGER.error("Can't parse StudyDate from query parameters : {}", e.getLocalizedMessage());
        }

        commonQueryParamMap.put(CommonQueryParams.LOWER_DATETIME, new String[] { lowerDateTime });
        commonQueryParamMap.put(CommonQueryParams.UPPER_DATETIME, new String[] { upperDateTime });

        legacyQueryParams.forEach(commonQueryParamMap::remove);
        return Collections.unmodifiableMap(commonQueryParamMap);

    }

    @Override
    public String getParameter(String name) {
        String[] params = queryParameterMap.get(name);
        return params != null ? params[0] : null;
    }

    @Override
    public String[] getParameterValues(String name) {
        return queryParameterMap.get(name);
    }

    @Override
    public Map<String, String[]> getParameterMap() {
            return queryParameterMap; // unmodifiable to uphold the interface contract.
        }

        @Override
        public Enumeration<String> getParameterNames() {
            return Collections.enumeration(queryParameterMap.keySet());
        }

        @Override
        public String getQueryString() {
            // @see : https://stackoverflow.com/a/35831692/9869013
            // return queryParameterMap.entrySet().stream().flatMap(entry -> Stream.of(entry.getValue()).map(value -> entry.getKey() + "=" + value)).collect(Collectors.joining("&")); // without encoding !!
            return queryParameterMap.entrySet().stream().flatMap(entry -> encodeMultiParameter(entry.getKey(), entry.getValue(), requestEncoding)).collect(Collectors.joining("&"));
        }

        private Stream<String> encodeMultiParameter(String key, String[] values, Charset encoding) {
            return Stream.of(values).map(value -> encodeSingleParameter(key, value, encoding));
        }

        private String encodeSingleParameter(String key, String value, Charset encoding) {
            return urlEncode(key, encoding) + "=" + urlEncode(value, encoding);
        }

        private String urlEncode(String value, Charset encoding) {
            try {
                return URLEncoder.encode(value, encoding.name());
            } catch (UnsupportedEncodingException e) {
                throw new IllegalArgumentException("Cannot url encode " + value, e);
            }
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            throw new UnsupportedOperationException("getInputStream() is not implemented in this " + CustomHttpServletRequest.class.getSimpleName() + " wrapper");
        }

    }

দ্রষ্টব্য: ক্যোয়ারিং স্ট্রিং () প্রতিটি কেইওয়াইয়ের জন্য সমস্ত মানগুলি প্রক্রিয়া করা প্রয়োজন এবং আপনার নিজস্ব প্যারাম মান যুক্ত করার সময় এনকোডআরল () ভুলেও ভুলবেন না, প্রয়োজন হলে

সীমাবদ্ধতা হিসাবে, আপনি যদি অনুরোধ করেন getgetParameterMap () বা যে কোনও পদ্ধতি যা অনুরোধকে কল করে getgetReader () এবং পড়া শুরু করেন, আপনি অনুরোধ.সেটচ্যাকার এঙ্কোডিং (...) এ আরও কোনও কল আটকাতে পারবেন will


0

স্যানিটাইজেশনের জন্য আপনি নিয়মিত এক্সপ্রেশন ব্যবহার করতে পারেন । চেইন.ডো ফিল্টার (অনুরোধ, প্রতিক্রিয়া) পদ্ধতি কল করার আগে ফিল্টারটির অভ্যন্তরে এই কোডটি কল করুন। এখানে নমুনা কোড:

for (Enumeration en = request.getParameterNames(); en.hasMoreElements(); ) {
String name = (String)en.nextElement();
String values[] = request.getParameterValues(name);
int n = values.length;
    for(int i=0; i < n; i++) {
     values[i] = values[i].replaceAll("[^\\dA-Za-z ]","").replaceAll("\\s+","+").trim();   
    }
}

1
আপনি মূল অনুরোধের পরামিতিগুলি এভাবে পরিবর্তন করবেন না, তবে একটি অনুলিপিতে।
মেহেদী

-1

ব্যবহার করে দেখুন request.setAttribute("param",value);। এটা আমার জন্য ভাল কাজ করেছিল.

দয়া করে এই কোডের নমুনাটি সন্ধান করুন:

private void sanitizePrice(ServletRequest request){
        if(request.getParameterValues ("price") !=  null){
            String price[] = request.getParameterValues ("price");

            for(int i=0;i<price.length;i++){
                price[i] = price[i].replaceAll("[^\\dA-Za-z0-9- ]", "").trim();
                System.out.println(price[i]);
            }
            request.setAttribute("price", price);
            //request.getParameter("numOfBooks").re
        }
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.