in my application, I enter the values of the three parameters, fromCurrency, toCurrency, and amount into the address bar
and in the controller. I want to check the correctness of the entered data. But I have generated an exception during the test and nothing goes further
Those. I need a code that in the controller will check the correctness of the entered data and, depending on the field in which the error was made, will produce a 400th error with the name of the incorrectly filled field
I'm tried this validation, with
if(!Currency.getAvailableCurrencies().contains(Currency.getInstance(fromCurrency)))
but it's generate exception if Currency doesn't contain fromCurrency
#RestController
class ExchangeController {
private static final Logger logger = Logger.getLogger(ExchangeController.class.getName());
#SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
#Autowired
#Qualifier("dataService")
private CurrencyExchangeService currencyExchangeService;
#SuppressWarnings("SameReturnValue")
#RequestMapping(value = "/", method = RequestMethod.GET, produces = "application/json")
public String start() {
return "input parameters";
}
#RequestMapping(value = "/convert", method = RequestMethod.GET, produces = "application/json")
public ExchangeRateDTO converting(#RequestParam("fromCurrency") String fromCurrency,
#RequestParam("toCurrency") String toCurrency,
#RequestParam("amount") String amount) throws IOException {
if (!Currency.getAvailableCurrencies().contains(Currency.getInstance(fromCurrency))) {
}
BigDecimal convertedAmount = currencyExchangeService.convert(fromCurrency, toCurrency, new BigDecimal(amount));
return new ExchangeRateDTO(fromCurrency, toCurrency, new BigDecimal(amount), convertedAmount);
}
}
You can use Hibernate Validator to validate the #RequestParam of your controller.
Add this dependency to your pom.xml
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.10.Final</version>
</dependency>
Then you have to enable validation for both request parameters and path variables in your controllers by adding the #Validated annotation like this
#RestController
#RequestMapping("/")
#Validated
public class Controller {
// ...
}
Then you can add Annotations like #NotNull #Min #Max to your RequestParam Like
#RequestMapping(value = "/convert", method = RequestMethod.GET, produces = "application/json")
public ExchangeRateDTO converting(#RequestParam("fromCurrency") #NotNull #NotBlank #Size(max = 10) String fromCurrency,
#RequestParam("toCurrency") String toCurrency,
#RequestParam("amount") String amount) throws IOException {
if (!Currency.getAvailableCurrencies().contains(Currency.getInstance(fromCurrency))) {
}
BigDecimal convertedAmount = currencyExchangeService.convert(fromCurrency, toCurrency, new BigDecimal(amount));
You can also define custom annotations for your needs.
There is more detailed and nice article here
Related
Here i'm trying to update an object and return the updated object in JSON format in a Spring REST controller.
Controller :
#RequestMapping(value = "/user/revert", method = RequestMethod.POST)
#Produces(javax.ws.rs.core.MediaType.APPLICATION_JSON)
public ResponseEntity<UserResponse> revertUserData(#RequestParam(value = "userName") String userName) {
User user = new User();
UserResponse userResponse = new UserResponse();
try {
user = userService.findUserByName(userName);
user.setLastName(null);
userResponse.setEmail(user.getEmail());
userResponse.setLastName(user.getLastName());
} catch (Exception e) {
return new ResponseEntity<UserResponse>(userResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<UserResponse>(userResponse, HttpStatus.OK);
}
UserResponse class :
#JsonInclude(JsonInclude.Include.NON_NULL)
public class UserResponse {
#JsonProperty("email")
private String email;
#JsonProperty("lastName")
private String lastName;
//getter and setter methids
}
pom file :
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.1</version>
</dependency>
The error im getting :
The target resource does not have a current representation that would be acceptable to the
user agent, according to the proactive negotiation header fields received in the request, and the server is
unwilling to supply a default representation.
You mixed JAX-RS and Spring MVC annotations: #RequestMapping comes from Spring and #Produces from JAX-RS. If you take a look at the #RequestMapping's documentation you'll see that it has a produces parameter. So you should have something like:
#RequestMapping(value = "/user/revert", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON)
public ResponseEntity<UserResponse> revertUserData(#RequestParam(value = "userName") String userName){
...
}
I am writing a feign client
#RequestMapping(
path = "/TrackingServlet?CompanyName=Test&UserName=&BranchCode=",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE
)
ResponseEntity<String> getInfo(
#RequestParam("DocumentNumbers") String bill);
when it is invoked the url becomes /TrackingServlet?CompanyName=Test&UserName&BranchCode
eliminating the = symbol, but the API needs it in that format, since its a third party API we cannot modify it.
Also tried
#RequestMapping(
path = "/TrackingServlet?CompanyName=Test&UserName=",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE
)
ResponseEntity<String> getInfo(
#RequestParam("DocumentNumbers") String bill,
#RequestParam(name = "BranchCode", required = true) String BranchCode);
default ResponseEntity<String> getInfo(String bill) {
return getInfo(bill, "");
}
this will not even have the param BranchCode
I am using org.springframework.cloud:spring-cloud-starter-openfeign:2.1.1.RELEASE
Spring boot version 2.1.4.RELEASE
is there anyway or workarounds for keeping empty params in urls as it is ?
If your URL is http://localhost:8080/trackingServlet/testing?userName=pratik
Use feign client:
#FeignClient(name = "tracking-servlet-service")
public interface TestFeignClient {
#GetMapping("/trackingServlet/testing")
public String getQueryParam(#RequestParam("userName") String name);
}
If you have 2 or more parameter then you can add same in #RequestParam
E.g
URL http://localhost:8080/trackingServlet/testing?userName=pratik&companyName=Test
#FeignClient(name = "tracking-servlet-service")
public interface TestFeignClient {
#GetMapping("/trackingServlet/testing")
public String getQueryParam(#RequestParam("userName") String name,
#RequestParam("companyName") String companyName);
}
I have implemented rest service and want to do validation on it. In my class I have #RequestBody and #RequestParam. I want to validate both objects. I do that like this:
#Controller
#Validated
public class RestApiImpl {
#Autowired
ClassA classA;
#ResponseBody
#RequestMapping(value = "/classA",
method = RequestMethod.POST,
produces = {MediaType.APPLICATION_JSON_VALUE},
consumes = {MediaType.APPLICATION_JSON_VALUE})
public ClassAResponse getList(#Valid #RequestBody ClassARequest request,
#Min(value = 1, message = "At least 1 object is expected")
#RequestParam(value = "quantity",defaultValue = "3",required = false) String quantity) {
return (ClassAResponse) classA.executeService(request);
}
}
public class ClassARequest {
#NotNull
#NotEmpty
#Size(max = 6, message = "tes1")
private String value1;
public String getValue1() {
return value1;
}
public void setValue1(String value1) {
this.value1 = value1;
}
}
And the post return 500 internal server error and log:
09:49:21,240 INFO [STDOUT] 09:49:21,240 ERROR [[dispatcher]] Servlet.service() for servlet dispatcher threw exception
javax.validation.ConstraintDeclarationException: Only the root method of an overridden method in an inheritance hierarchy may be annotated with parameter constraints, but there are parameter constraints defined at all of the following overridden methods:
When I remove #Validated #RequestBody is validated and works fine but validation for #RequestParam is not working. And If I remove #Valid from #RequestBody validation for request is not working. How to configure this that it work for both #RequestBody and #RequestParam. Or there isn't any solution and only way is to move param quantity to request?
spring framework 3.2.18.RELEASE and hibernate-validator 4.2.0.Final (it can't be changed to newer version for spring and hibernate)
I am building web service with spring and come across with following problem.
There is a post service as follow.
#RequestMapping(value = "/postSomething", method = RequestMethod.POST)
public ResponseDTO postSomething(#RequestBody ADto aDto){
//post data
//return response
}
public class ADto{
private String firstParam;
private String secondParam;
// getter setter
}
So, my question is how can I know whether value of firstParam and secondParam is provided in request body or not.
RequestBody: { paramFirst: null, paramSecond: null}
Edit1:
Sorry for incomplete question:
For RequestBody: {paramFirst: first Value} and for above request value of paramSecond will be null.
So, how would I know whether paramSecond is included in request or not.
Edit2:
I don't want to validate. What I want to know is whether
request contains a particular parameter or not.
Because there are two different cases, one is value of a parameter is given null and other is paramter is not included in request.
You could use the #Valid annotation like so (pseudo code, didn't test it):
#RequestMapping(value = "/postSomething", method = RequestMethod.POST)
public ResponseDTO postSomething(#Valid #RequestBody ADto aDto){
// MethodArgumentNotValidException will be thrown if validation fails.
}
You'll need an exception handler to handle the validation error.
#ExceptionHandler
#ResponseBody
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public Error handleException(MethodArgumentNotValidException exception) {
//do something with the validation message: exception.getBindingResult()
}
And your class.
public class ADto{
#NotNull(message = "First parameter can not be null")
private String firstParam;
#NotNull(message = "Second parameter can not be null")
private String secondParam;
// getter setter
}
Try using Hibernate Validator (http://hibernate.org/validator/), it's really easy to integrate it with Spring.
That way, you'll need to annotate your Dto to enforce validation of required params and then call validate.
public class ADto{
#NotNull
private String firstParam;
#NotNull
private String secondParam;
// getter setter
}
#RequestMapping(value = "/postSomething", method = RequestMethod.POST)
public ResponseDTO postSomething(#RequestBody ADto aDto){
validator.validate(aDto)
//post data
//return response
}
You could make firstParam and secondParam type Optional:
ADto class
public class ADto {
private Optional<String> firstParam;
private Optional<String> secondParam;
// getter setter
}
postSomething method
#RequestMapping(value = "/postSomething", method = RequestMethod.POST)
public ResponseDTO postSomething(#RequestBody ADto aDto) {
if (Optional.ofNullable(aDto.getFirstParam()).isPresent()) {
// firstParam is provided in the request
} else {
// firstParam is not provided in the request
}
if (Optional.ofNullable(aDto.getSecondParam()).isPresent()) {
// secondtParam is provided in the request
} else {
// secondtParam is not provided in the request
}
}
Note that isPresent() will return false if and only if firstParam (as well as for secondParam) is not present in the request. Otherwise, even if the value is set to null, it will return true.
I need to handle requests as following:
www.example.com/show/abcd/efg?name=alex&family=moore (does not work)
www.example.com/show/abcdefg?name=alex&family=moore (works)
www.example.com/show/abcd-efg?name=alex&family=moore (works)
It should accept any sort of character from the value that is located between www.example.com/show/ and ?. Please note the value that would be located there would be a single value not name of an action.
For example: /show/abcd/efg and /show/lkikf?name=Jack in which the first request should redirect user to the page abcd/efg (because thats a name) and the second one should redirect user to the page lkikf along with value of parameter name.
I have following controller to handle it but the issue is when I have / in the address the controller is unable to handle it.
#RequestMapping(value = "/{mystring:.*}", method = RequestMethod.GET)
public String handleReqShow(
#PathVariable String mystring,
#RequestParam(required = false) String name,
#RequestParam(required = false) String family, Model model) {
I used following regex which did not work.
/^[ A-Za-z0-9_#./#&+-]*$/
Another way I do is:
#RequestMapping(value = "test_handler/**", method = RequestMethod.GET)
...and your test handler can be "/test_hanlder/a/b/c" and you will get the whole value using following mechanism.
requestedUri = (String)
request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
You have to create two methods then one having the #RequestMapping(value = { "/{string:.+}" }) annotation and the other having #RequestMapping(value = { "/{string:.+}", "/{string:.+}/{mystring:.+}" }) and then act accordingly in each, because you can't have optional path variables.
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
#Controller
#RequestMapping("/show")
public class HelloController {
#RequestMapping(value = { "/{string:.+}" })
public String handleReqShow(#PathVariable String string,
#RequestParam(required = false) String name,
#RequestParam(required = false) String family, Model model) {
System.out.println(string);
model.addAttribute("message", "I am called!");
return "hello";
}
#RequestMapping(value = { "/{string:.+}", "/{string:.+}/{mystring:.+}" })
public String whatever(#PathVariable String string,
#PathVariable String mystring,
#RequestParam(required = false) String name,
#RequestParam(required = false) String family, Model model) {
System.out.println(string);
System.out.println(mystring);
model.addAttribute("message", "I am called!");
return "hello";
}
}
The first one is not working because you are trying to handle an entirely new URL which is not actually mapped your controller.
www.example.com/show/abcd/efg?name=alex&family=moore (does not work)
The correct mapping for the above URL could be like the below code.
#RequestMapping(value = {"/{mystring:.*}" , "/{mystring:.*}/{mystring2:.*}"}, method = RequestMethod.GET)
public String handleReqShow(
#PathVariable String mystring,
#PathVariable String mystring2,
#RequestParam(required = false) String name,
#RequestParam(required = false) String family, Model model) {
I have tried the similar concept when my one controller is used to handle multiple types of request.
You could encode slashes on UI with %2f: http://www.example.com/show/abcd%2fefg?name=alex&family=moore.
Now you should configure Spring to handle slashes. Simple config example:
#RestController
public class TestController {
#GetMapping("{testId:.+}")
public String test(#PathVariable String testId) {
return testId;
}
#GetMapping("{testId:.+}/test/{messageId}")
public String test2(#PathVariable String testId, #PathVariable String messageId) {
return testId + " " + messageId;
}
//Only if using Spring Security
#Configuration
public static class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
DefaultHttpFirewall firewall = new DefaultHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
return firewall;
}
#Override
public void configure(WebSecurity web) throws Exception {
web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
}
}
#Configuration
#Order(Ordered.HIGHEST_PRECEDENCE)
public static class SpringMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setUrlDecode(false);
configurer.setUrlPathHelper(urlPathHelper);
}
}
}
The default Spring MVC path mapper uses the / as a delimiter for path variables, no matter what.
The proper way to handle this request would be to write a custom path mapper, that would change this logic for the particular handler method and delegate to default for other handler methods.
However, if you know the max possible count of slashes in your value, you can in fact write a handler that accepts optional path variables, and than in the method itself, assemble the value from path variable parts, here is an example that would work for max one slash, you can easily extend it to three or four
#RequestMapping(value = {"/{part1}", "/{part1}/{part2}"}, method = RequestMethod.GET)
public String handleReqShow(
#PathVariable Map<String, String> pathVariables,
#RequestParam(required = false) String name,
#RequestParam(required = false) String family, Model model) {
String yourValue = "";
if (pathVariables.containsKey("part1")) {
String part = pathVariables.get("part1");
yourValue += " " + part;
}
if (pathVariables.containsKey("part2")) {
String part = pathVariables.get("part2");
yourValue += " /" + part;
}
// do your stuff
}
You can catch all the path variables inside the map, the map #PathVariable Map<String, String> pathVariables, but the downside is that the static part of the mapping has to enumarate all the possible variations
You can define rules to avoid that
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
rules.xml add this to your WEB-INF
<urlrewrite>
<rule>
<from>^/(10\..*)$</from> <!-- tweak this rule to meet your needs -->
<to>/Show?temp=$1</to>
</rule>
</urlrewrite>
Try escaping forward slash.
Regex: /^[ A-Za-z0-9_#.\/#&+-]*$/