combining methods with same flow in controller. - spring

Method 1.
#RequestMapping(value="/getProfessor")
public #ResponseBody List<Object> getMember(HttpServletRequest request){
HttpSession session = request.getSession();
HashMap user = (HashMap)session.getAttribute("USER_INFO");
Map<String, Object> param = new HashMap<String, Object>();
param.put("phone", (String)user.get("PHONE");
ReportManager manager = new ReportManager();
List<Object> list = manager.getProfessor(param);
}
Method 2.
#RequestMapping(value="/getMember")
public #ResponseBody List<Object> getMember(HttpServletRequest request){
HttpSession session = request.getSession();
HashMap user = (HashMap)session.getAttribute("USER_INFO");
Map<String, Object> param = new HashMap<String, Object>();
param.put("phone", (String)user.get("PHONE");
ReportManager manager = new ReportManager();
List<Object> list = manager.getMember(param);
}
The code above briefly describe how I get list of members and professors.
The two methods have exactly same code flow except URL and the bottom-most methods. As you know, one of core principles in OOP is 'combine repeating problems'. So, the point is that I want to combine these method into one method.

public Map<String, Object> getParams(HttpServletRequest request){
HttpSession session = request.getSession();
HashMap user = (HashMap)session.getAttribute("USER_INFO");
Map<String, Object> param = new HashMap<String, Object>();
param.put("phone", (String)user.get("PHONE");
}
#RequestMapping(value="/getProfessor")
public #ResponseBody List<Object> getMember(HttpServletRequest request){
ReportManager manager = new ReportManager();
List<Object> list = manager.getProfessor(this.getParams(request));
}
#RequestMapping(value="/getProfessor")
public #ResponseBody List<Object> getMember(HttpServletRequest request){
ReportManager manager = new ReportManager();
List<Object> list = manager.getProfessor(this.getParams(request));
}

Agree with you, as per DRY coding principle duplicating the same code is not recommended.
Either you can use single RequestMapping with some kind of query parameter, OR
move the common code to different method, and invoke it from two methods.

Change the url to a more generic url like /getUser.
Pass an additional TYPE param like PROFESSOR/MEMBER in the request. Depending on the TYPE you can query two different methods in your controller method.

Related

Spring WebFlux WebSocket path variable

How can I get path variable in websocket handler with spring webflux?
I've tried this:
#Bean
public HandlerMapping webSocketMapping() {
Map<String, WebSocketHandler> map = new HashMap<>();
map.put("/path/{id}", session -> session.send(Mono.just(session.textMessage("123"))));
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setUrlMap(map);
mapping.setOrder(-1);
return mapping;
}
But session doesn't have any information about url parameters.
Is it possible?
It requires some casting but it is possible.
private URI getConnectionUri(WebSocketSession session) {
ReactorNettyWebSocketSession nettySession = (ReactorNettyWebSocketSession) session;
return nettySession.getHandshakeInfo().getUri();
}
Once you have the URI use the Spring UriTemplate to get path variables.
// This can go in a static final
UriTemplate template = new UriTemplate("/todos/{todoId}");
Map<String, String> parameters = template.match(uri.getPath());
String todoId = parameters.get("todoId");

Do you have an example to use CUD ODataXXXRequestBuilders

In all the documentation I found examples for ODataQueryBuilder.
But do you also have an example how to use the Create, Update and Delete methods of the package com.sap.cloud.sdk.odatav2.connectivity:
ODataCreateRequestBuilder
ODataDeleteRequestBuilder
ODataUpdateRequestBuilder
How is the CSRF token handled?
Please provide a working example?
CSRF tokens are fetched with a HEAD request on the metadata endpoint of the OData service.
Some notes:
The following examples assume that you have a destination named "DestinationName" configured in the SAP Cloud Platform cockpit.
Please keep in mind that the S/4HANA virtual data model is usually the easier alternative.
ODataCreateRequestBuilder
Map<String, Object> body = new HashMap<>();
body.put("FirstName", "John");
body.put("LastName", "Doe");
body.put("BusinessPartnerCategory", "1");
ODataCreateRequest createRequest =
ODataCreateRequestBuilder
.withEntity("/sap/opu/odata/sap/API_BUSINESS_PARTNER", "A_BusinessPartner")
.withBodyAsMap(body)
.build();
createRequest.execute("DestinationName");
ODataUpdateRequestBuilder
Map<String, Object> keys = new HashMap<>();
keys.put("BusinessPartner", "12345");
Map<String, Object> params = new HashMap<>();
params.put("FirstName", "John");
params.put("MiddleName", "D.");
params.put("LastName", "Doe");
params.put("BusinessPartnerCategory", "1");
final ODataUpdateRequest updateRequest =
ODataUpdateRequestBuilder
.withEntity("/sap/opu/odata/sap/API_BUSINESS_PARTNER", "A_BusinessPartner", keys)
.withBodyAsMap(params)
.build();
updateRequest.execute("DestinationName");
ODataDeleteRequestBuilder
Map<String, Object> keys = new HashMap<>();
keys.put("BusinessPartner", "12345");
keys.put("AddressID", "98765");
ODataDeleteRequest deleteRequest =
ODataDeleteRequestBuilder
.withEntity("/sap/opu/odata/sap/API_BUSINESS_PARTNER", "A_BusinessPartnerAddress", keys)
.build();
deleteRequest.execute("DestinationName");

Return list of values on ajax success in spring MVC

I am looking for returning a list of values after ajax success in spring mvc
#RequestMapping(value = "/getAlertNotification.ftl")
public ModelAndView getAlertNotification(HttpServletRequest request
){
Map<Object, Object> model = new HashMap<Object, Object>();
User user = RequestUtils.getUser(request);
List<CardRequestNotification> Cardreqlist=cardRequestManager.cardRequestNotification(user);
model.put("listObj", Cardreqlist);
return new ModelAndView(new JSONView(model));
}
$("#alertLink").click(function()
{ var $this = j$(this);
GtsJQuery.ajax(GtsJQuery.getContextPath()
+ "/getAlertNotification.ftl",
function(data) {
/* how i return Cardreqlist object list`enter code here` in here */
});
I guess you are having a misunderstanding concept, if you are trying to return a ModelAndView then you need to specify the JSP file or HTML template which will be rendered, and you need the specific ModelAndView name.
But you are mixing Views and JSON, which is for AJAX calls, so i guess your code would be something more like this:
#RequestMapping(value = "/getAlertNotification.ftl")
#ResponseBody
public List<CardRequestNotification> getAlertNotification(HttpServletRequest request) {
Map<Object, Object> model = new HashMap<Object, Object>();
User user = RequestUtils.getUser(request);
List<CardRequestNotification> Cardreqlist = cardRequestManager.cardRequestNotification(user);
model.put("listObj", Cardreqlist);
return Cardreqlist;
}
Then in your JS code, you could do:
data.Cardreqlist

Spring RestRemplate postforobject with request parameter having integer value

I have a method in Spring rest service.
#RequestMapping(value = "test/process", method = RequestMethod.POST)
public #ResponseBody MyResponse processRequest(String RequestId, int count)
I am using Spring RestTemplate to call this service like this.
RestTemplate restTemplate = this.getRestTemplate();
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("RequestId", RequestId);
map.add("count", count);
restTemplate.postForObject(url, map,MyResponse.class);
When I try to invoke the client method I get the exception that no suitable HttpMessageConverter found for request type [java.lang.Integer]
org.springframework.http.converter.HttpMessageNotWritableException: Could not write request: no suitable HttpMessageConverter found for request type [java.lang.Integer]
at org.springframework.http.converter.FormHttpMessageConverter.writePart(FormHttpMessageConverter.java:310)
at org.springframework.http.converter.FormHttpMessageConverter.writeParts(FormHttpMessageConverter.java:270)
at org.springframework.http.converter.FormHttpMessageConverter.writeMultipart(FormHttpMessageConverter.java:260)
at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:200)
at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:1)
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:596)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:444)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:409)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:287)
I know one of the ways is to pass all the parameters as String. But I might need to pass complex data types as parameters later.
What is the ways to achieve this.
I have googled and some option seem to be writing my own converters. How should I start about solving this problem.
The root cause of this error is that by specifying an Integer in the LinkedMultiValueMap, the RestTemplate will take that to mean that your request is a multipart request. There is no HttpMessageConverter registered by default that can handle writing values of type Integer to a request body.
As you said, you can handle this situation by changing the count to be a String. After all, there is no Integer type in HTTP request parameters. However, you were worried
But I might need to pass complex data types as parameters later.
Assume something like this
public #ResponseBody MyResponse processRequest(String RequestId, int count, Complex complex) {
with
public class Complex {
private String someValue;
private int intValue;
public String getSomeValue() {
return someValue;
}
public void setSomeValue(String someValue) {
this.someValue = someValue;
}
public int getIntValue() {
return intValue;
}
public void setIntValue(int intValue) {
this.intValue = intValue;
}
public String toString() {
return someValue + " " + intValue;
}
}
The the following will work just fine
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("RequestId", "asd");
map.add("count", "42");
map.add("someValue", "complex");
map.add("intValue", "69");
restTemplate.postForObject(url, map,MyResponse.class);
Remember that the request parameters are used to populate the fields of model attributes by their names.
An even better solution would have you using a serialization standard like JSON or XML.

RestTemplate post for entity

My post method gets called but my Profile is empty. What is wrong with this approach? Must I use #Requestbody to use the RestTemplate?
Profile profile = new Profile();
profile.setEmail(email);
String response = restTemplate.postForObject("http://localhost:8080/user/", profile, String.class);
#RequestMapping(value = "/", method = RequestMethod.POST)
public #ResponseBody
Object postUser(#Valid Profile profile, BindingResult bindingResult, HttpServletResponse response) {
//Profile is null
return profile;
}
You have to build the profile object this way
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
parts.add("email", email);
Object response = restTemplate.postForObject("http://localhost:8080/user/", parts, String.class);
MultiValueMap was good starting point for me but in my case it still posted empty object to #RestController my solution for entity creation and posting ended up looking like so:
HashedMap requestBody = new HashedMap();
requestBody.put("eventType", "testDeliveryEvent");
requestBody.put("sendType", "SINGLE");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// Jackson ObjectMapper to convert requestBody to JSON
String json = new ObjectMapper().writeValueAsString(request);
HttpEntity<String> entity = new HttpEntity<>(json, headers);
restTemplate.postForEntity("/generate", entity, String.class);
My current approach:
final Person person = Person.builder().name("antonio").build();
final ResponseEntity response = restTemplate.postForEntity(
new URL("http://localhost:" + port + "/person/aggregate").toString(),
person, Person.class);

Resources