I have created a api endpoint using spark for education purpose. Now i need to convert this implementation to the springboot and need to consume the request parameter within the implementation.Following codes show how i have implemented both application...But how can i consume request from spring boot application. Following implementation wont give the request body.
package com.spark2springboot.application;
import static spark.Spark.*;
public class spark2SpringbootTest {
public static void main(String[] args) {
post("/api/spark2springboot/receive", (request, response) -> {
String str = new String(request.bodyAsBytes());
return str;
});
}
}
Spring boot implementation
#RestController
public class EmailMessageController {
#PostMapping(path = "/api/spark2springboot/receive", consumes = "application/json", produces = "application/json")
public void spark2springboot(HttpServletRequest request, HttpServletResponse response,) {
String str = CharStreams.toString(request.getReader());
return str;
}
}
Simply refer to 'https://www.baeldung.com/spring-request-response-body'. For more information, see the official documentation.
Related
I'm not able to bind an attribute that I'm setting from a WebTestClient into a RestController when using Spring WebFlux.
I tried the two ways I could think of.
First using the #RequestAttribute annotation and I got:
Failed to handle request [GET /attributes/annotation]: Response status 400 with reason "Missing request attribute 'attribute' of type String"
Then I tried with the ServerWebExchange and was null.
This is my controller:
#RestController
#RequestMapping("/attributes")
public class MyController {
#GetMapping("/annotation")
public Mono<String> getUsingAnnotation(#RequestAttribute("attribute") String attribute) {
return Mono.just(attribute);
}
#GetMapping("/exchange")
public Mono<String> getUsingExchange(ServerWebExchange exchange) {
return Mono.just(exchange.getRequiredAttribute("attribute"));
}
}
And this is my failing test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyControllerTest {
#Autowired
ApplicationContext context;
WebTestClient webClient;
#Before
public void setup() {
webClient = WebTestClient.bindToApplicationContext(context)
.configureClient()
.build();
}
#Test
public void testGetAttributeUsingAnnotation() {
webClient.get()
.uri("/attributes/annotation")
.attribute("attribute", "value")
.exchange()
.expectStatus()
.isOk();
}
#Test
public void testGetAttributeUsingExchange() {
webClient.get()
.uri("/attributes/exchange")
.attribute("attribute", "value")
.exchange()
.expectStatus()
.isOk();
}
}
In my real application I have a SecurityContextRepository that sets some attributes from a (decoded) header value and I'd like to get those attributes.
I've run into the same issue with a test which previously used MockMvc and then had to be converted to use WebClient. Like #jcfandino I was expecting the .attribute() methods on the WebClient to work similar to MockMvc's requestAttribute().
I haven't found out how .attribute() is meant to be used but I've bypassed the entire problem by adding a custom test filter. I'm not sure if this approach is correct but since this question has been unanswered the approach below may be of help for people running into the same issue.
#WebFluxTest(controllers = SomeController.class)
#ComponentScan({ "com.path1", "com.path2" })
class SomeControllerTest {
// define a test filter emulating the server's filter (assuming there is one)
private class AttributeFilter implements WebFilter {
String attributeValue;
public AttributeFilter(String filterAttributeValue) {
attributeValue = filterAttributeValue;
}
#Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
// add the desired attributes
exchange.getAttributes().put(SomeController.ATTR_NAME, attributeValue);
return chain.filter(exchange);
}
}
// mock the service the controller is dependend on
#MockBean
AppService appService;
// define the test where the controller handles a get() operation
#Test
void testMethod() {
// mock the app service
when(appService.executeService(anyString(), anyString())).thenAnswer(input -> {
// ... return some dummy appData
});
var testClient= WebTestClient.bindToController(new SomeController(appService))
.webFilter(new SomeControllerTest.AttributeFilter("someValue"))
.build();
try {
var response = testClient
.get()
.uri("someroute")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk()
.expectBody(AppData.class);
} catch (Exception e) {
fail("exception caught in testMethod", e);
}
}
}
Both on the server and client side, request attributes should be seen as Map-like data structures that can be used to transfer information within the client/server (for filters, codecs, etc).
That information is not sent over the network.
If you want to send that information from the client to the server, you should take a look at request params or the request body itself.
I am working on the Spring Boot web application. I am running two different application one for service (Rest Resource) and other one is UI which show the request on HTML page on the bases of response got on the rest request.
My all rest services are created by
#Component
#Api(value = "/api/1/registration", description = "Access and manage your information")
#Path("/api/1/registration")
#Produces(MediaType.APPLICATION_JSON)
#Slf4j
public class RegistrationResource {
...
...
#ApiOperation(value = "Find user by id", notes = "Return a user by id", response = Registration.class)
#Path("/{id}")
#GET
#Timed
#Override
public Registration get(#PathParam("id") String id) {
// my logic
}
}
Restangular Request
Restangular.one("registration/1").get().then(function (data) {
...
},function(error) {
...
});
When I do restangular request from ui, its working fine. Now I need to have a servlet resource. For that I create new resource class
#Slf4j
#RestController
#RequestMapping("/api/1/test")
public class DownloadResource{
#RequestMapping(value = "/downloadtesting", method = RequestMethod.GET)
public void download(HttpServletResponse response, HttpServletRequest request){
// I need to call this method... How can I
}
}
FYI: All my resources are registered as following...
Reflections reflections = new Reflections("com.sample.resource");
Set<Class<? extends Object>> resources =
reflections.getTypesAnnotatedWith(Path.class); //
resources.forEach(r -> {
log.debug("Registering resource " + r);
register(beanFactory.getBean(r));
});
// Same I did for RequestMapping.class also but I am getting 404 error for downloadtesting api.
NOTE: If I try with following version for downloadtesting in RegistrationResource then I am getting HttpServletRequest / Response null.
public class RegistrationResource{
#Path("/downloadtesting")
public void download(HttpServletResponse response, HttpServletRequest request){
// I need to call this method... How can I
}
}
Can any one help me?
I have a Windows service "A" being used for authentication purposes (NOT managed by us) and I have Spring-boot based REST Api service "B" (managed by us) which uses Zuul to route traffic. There is an external service "C" (NOT managed by us) that needs to talk to the Windows service through our REST Apis. Since "A" uses NTLM authentication we need to pass the request body from "C" and add the ntlm credentials in the headers at "B" and route the traffic using zuul.
My question is, how do I add NTLM credentials in Java to the routed traffic in zuul headers?
~ Jatin
You need to write your own ZuulFilter.
Something along the lines of
import javax.servlet.http.HttpServletRequest;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.ZuulFilter;
public class MyFilter extends ZuulFilter {
#Override
public String filterType() {
return "pre";
}
#Override
public int filterOrder() {
return 1;
}
#Override
public boolean shouldFilter() {
return true;
}
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
// now add your headers to the request
return null;
}
}
In your app just make sure the filter bean is created and it will be automatically registered:
#EnableZuulProxy
#SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
#Bean
public MyFilter myFilter() {
return new MyFilter();
}
}
Have a look at this guide for more info.
Zuul will work fine with Spring Session. There are many blogs about this.
http://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot.html
I'm using Java 8, Tomcat 8, Spring-WebMVC 4.2.2.RELEASE, FasterXML 2.6.3.
I have the following method in my controller
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public void updateCurrentUserDetails(#RequestBody final UserDTO userDTO) {
final UserWithId user = SecurityUtil.getCurrentUser();
this.userAccountService.updateUserDetails(user.getUserId(), user.getUsername(), userDTO);
}
This method returns void which resolves in an empty (0 byte) response. However the clients connecting to the server always expect JSON reponses even, if its an empty response.
So I would like to configure Spring/Jackson to return {} (2 byte) in that case.
I already thought about returning new Object() everywhere in the calls that would return void otherwise but IMO this is a dirty soution and there must be something better.
There shouldn't be any need to do all that. You can just use a 204 response code, which is made for the situation you are describing. You don't even need the ResponseBody annotation, just use:
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void updateCurrentUserDetails(#RequestBody final UserDTO userDTO) {
final UserWithId user = SecurityUtil.getCurrentUser();
this.userAccountService.updateUserDetails(user.getUserId(), user.getUsername(), userDTO);
}
204 response code:
The 204 (No Content) status code indicates that the server has
successfully fulfilled the request and that there is no additional
content to send in the response payload body.
Its quite easy.
Just add the following to your spring xml/java config
<mvc:interceptors>
<bean class="de.st_ddt.util.VoidResponseHandlerInterceptor" />
</mvc:interceptors>
And add this class to your classpath
public class VoidResponseHandlerInterceptor extends HandlerInterceptorAdapter {
private static final String voidResponse = "{}";
#Override
public void postHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler,
final ModelAndView modelAndView) throws IOException {
// Returned void?
if (!response.isCommitted()) {
// Used ModelAndView?
if (modelAndView != null) {
return;
}
// Access static resource?
if (DefaultServletHttpRequestHandler.class == handler.getClass()) {
return;
}
response.setStatus(200);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
try (final Writer writer = response.getWriter()) {
writer.write(voidResponse);
}
response.flushBuffer();
}
}
}
I have wrote spring rest Async controller, that return String JSON response,
When I request the browser complete the response, while the controller have not completed the processing hence the response is not ready.
I am using Spring Boot, Apache as inbuilt server.
In EmbeddedServletContainerFactory I have set AsyncTimeout too.
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
#Override
public void customize(Connector connector) {
connector.setAsyncTimeout(10000000);
}
});
so How I make the browser wait while the controller Async'ly complete the response?
And the controller is
#Async
#RequestMapping(value = "/id", method = RequestMethod.GET)
public String getDetails(#PathVariable("id") String id) {
// wrote logic for JSON response....
}