What's the best way to encode and decode parameter in springboot?
Asked Answered
P

3

10

I use @RequestParam to get the parameter value,but I find the if I pass the value like 'name=abc&def&id=123',I will get the name value 'abc' instead of 'abc&def'. I find the encode and decode the parameter value can solve my problem.But I have to write the encode and decode mehtod in every controller method,Do spring have the global mehtod that decode every @RequestParam value?When using @RequestParam, is it necessary to encode and decode every value?

Here is my code:

@PostMapping("/getStudent")
public Student getStudent(
        @RequestParam String name,
        @RequestParam String id) { 
        name= URLDecoder.decode(name, "UTF-8");  
        //searchStudent
        return Student;
}

@PostMapping("/getTeacher")
public teacher getTeacher(
        @RequestParam String name,
        @RequestParam String teacherNo) { 
        name= URLDecoder.decode(name, "UTF-8");  
        //searchTeacher
        return teacher;
}

Somebody say the the Spring will have already done this,but I have try,the result is not right.Only use curl cmd is ok,but java code is not ok.

@PostMapping(value = "/example")
public String handleUrlDecode1(@RequestParam String param) { 
    //print ello%26test
    System.out.println("/example?param received: " + param); 
    return "success";
}

@GetMapping(value = "/request")
public String request() {
    String url =  "http://127.0.0.1:8080/example?param=ello%26test";
    System.out.println(url);
    RestTemplate restTemplate = new RestTemplate();
    return restTemplate.postForObject(url, null, String.class);
}
Peregrine answered 19/7, 2022 at 13:45 Comment(3)
If you pass name=abc&def&id=123 then you have parameters name, def and id, not just name and id. If you want name to have value abc&def, then the & needs to be encoded as %26, so the value is abc%26def. The call the URLDecoder.decode shouldn't be necessary, as Spring will have already done this for you.Stylist
@MarkRotteveel,I have to call URLDecoder.decode,otherwise I will get abc%26def, I use restTemplate.postForObject to send the requestPeregrine
See updates on my answer. The issue you are seeing is RestTemplate is automatically url encoding html entities for you. If you pass "&" it will encode it, and the Controller will also automatically decode it too. If you pass "%26" it passes it as a literal string containing "%26"Cultus
S
2

You must create an HTTP entity and send the headers and parameter in body.

@GetMapping(value = "/request")
public String request()  {
    String url =  "http://127.0.0.1:8080/example";
    System.out.println(url);
    RestTemplate restTemplate = new RestTemplate(); 
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
    map.add("param","ello&test");
    map.add("id","ab&c=def");
    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers); 
    return restTemplate.postForObject(url, request, String.class);
}
Sandor answered 20/7, 2022 at 14:36 Comment(0)
H
2

As you can read here, the escape character for & is %26.

So you should use the following

name=abc%26def&id=123

If you don't use an escape character according to URL standards, Spring will try to use what follows & and try to match it as a new query parameter.

Humdrum answered 19/7, 2022 at 15:39 Comment(0)
S
2

You must create an HTTP entity and send the headers and parameter in body.

@GetMapping(value = "/request")
public String request()  {
    String url =  "http://127.0.0.1:8080/example";
    System.out.println(url);
    RestTemplate restTemplate = new RestTemplate(); 
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
    map.add("param","ello&test");
    map.add("id","ab&c=def");
    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers); 
    return restTemplate.postForObject(url, request, String.class);
}
Sandor answered 20/7, 2022 at 14:36 Comment(0)
C
1

No need to manually use URLDecoder, SpringBoot controllers will handle it for you.

@RestController
public class UrlDecodeController {

    @GetMapping(value = "/example")
    public String handleUrlDecode(@RequestParam String param) {
    
        System.out.println("/example?param received: " + param);
    
        return "success";
    }

    @PostMapping(value = "/example2")
    public String handleUrlDecodeInPostRequest(@RequestParam String param1, ExamplePayload payload) {
        System.out.println("/example2?param1 received: " + param1);
        System.out.println("request body - value1: " + payload.getValue1());
    
        return "success";
    }

    @GetMapping(value = "/request")
    public String request() {
        String url =  "http://localhost:8080/example2?param1=test1&test2";
        System.out.println(url);
        RestTemplate restTemplate = new RestTemplate();
    
        HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    
        MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
        map.add("value1","test1&test2");
    
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers); 
    
        return restTemplate.postForObject(url, request, String.class);
    }


    class ExamplePayload{
    
        private String value1;
        private String value2;
    
        //getters and setters

        public ExamplePayload() {
        }
    }
}

Call with GET /example?param=hello%26test and the System.out.println outputs:

/example?param received: hello&test

Call the POST using curl as an example:

curl -X POST "http://localhost:8080/example2?param1=test1%26test2" -d "value1=test3%26test4"

Prints:

/example2?param1 received: test1&test2

request body - value1: test3&test4

Added GET /request to show using RestTemplate with the application/x-www-form-urlencoded Content-Type. Note that RestTemplate will automatically url encode any values passed as request parameters or in the request body. If you pass a String value of "%26" it will pass it as is, this is what you are seeing in your example. If you pass "&" it will url encode it to "%26" for you, and the Controller decodes it automatically on the other side.

Cultus answered 19/7, 2022 at 19:56 Comment(6)
How about PostMapping?My controller do not decode it automatically when I use restTemplate.postForObject.Peregrine
In my controller I use default tomcat in springbootPeregrine
I have the test example in the question body.Peregrine
PostMappng works the same way, updating my answer with a example for that tooCultus
If your example is working with curl ok then this shows it is being handled by your Controller ok. Check how your client is sending the request.Cultus
When sending the request with RestTemplate I think you also need to send a MediaType.APPLICATION_FORM_URLENCODED header for it to work.Cultus

© 2022 - 2024 — McMap. All rights reserved.