I am new at webservices and currently able to run my query by calling https://localhost/application/service/v1.0/contacts/account={accountId}
I want to make my url look like https://localhost/application/service/v1.0/contacts?account={accountId}
May I know How to achieve this not using QueryParam ? I am working in spring mvc
#Controller
public class ContactListResponseController extends BaseWebServiceController
{
public static final String PATH = "/v" + VERSION + "/contacts/account={accountId}";
#Autowired
private ContactService contactService;
#RequestMapping(value = PATH, method = RequestMethod.GET)
#ResponseBody
public ContactListResponseBean doGetMyAssignedAccounts (#PathVariable String accountId,
HttpServletRequest request,
HttpSession session,
HttpServletResponse response,
#ModelAttribute(User.USER_REQUEST_VAR) User user)
throws Exception
{
List<ContactSummaryWebServiceBean> contactList = contactService.getContactsListForCallPointWebService(accountId);
ContactListResponseBean result = new ContactListResponseBean(contactList);
return result;
}
}
It is a simple thing, try this:
#Controller
public class ContactListResponseController extends BaseWebServiceController
{
public static final String PATH = "/v" + VERSION + "/contacts";
#Autowired
private ContactService contactService;
#RequestMapping(value = PATH, method = RequestMethod.GET)
#ResponseBody
public ContactListResponseBean doGetMyAssignedAccounts (#RequestParam("account") String accountId,
HttpServletRequest request,
HttpSession session,
HttpServletResponse response,
#ModelAttribute(User.USER_REQUEST_VAR) User user)
throws Exception
{
List<ContactSummaryWebServiceBean> contactList = contactService.getContactsListForCallPointWebService(accountId);
ContactListResponseBean result = new ContactListResponseBean(contactList);
return result;
}
}
This sample.
#RequestMapping("/pets/{petId}")
public void findPet(#PathVariable String ownerId, #PathVariable String petId, Model model) {
// implementation omitted
}
Your code.
#Controller
public class ContactListResponseController extends BaseWebServiceController
{
public static final String PATH = "/v" + VERSION + "/contacts/{accountId}";
#Autowired
private ContactService contactService;
#RequestMapping(value = PATH, method = RequestMethod.GET)
#ResponseBody
public ContactListResponseBean doGetMyAssignedAccounts (#PathVariable String accountId,
HttpServletRequest request,
HttpSession session,
HttpServletResponse response,
#ModelAttribute(User.USER_REQUEST_VAR) User user)
throws Exception
{
List<ContactSummaryWebServiceBean> contactList = contactService.getContactsListForCallPointWebService(accountId);
ContactListResponseBean result = new ContactListResponseBean(contactList);
return result;
}
}
Ajax url = "/v" + VERSION + "/contacts/" + accountId,
:D
Related
pls find below my controller class and service class
#RequestMapping(value = "/offers/{jobTitle}/applications", method = RequestMethod.POST, consumes = {
"multipart/form-data" })
public ResponseEntity<Object> uploadMultipartFile(#RequestPart("file") MultipartFile file,
#PathVariable String jobTitle, #RequestParam("applicationStatus") String applicationStatus,
#RequestParam("name") String name, #RequestParam("emailId") String emailId) throws IOException {
Application app = applicationService.createApplicationMultipartFile(file, jobTitle, applicationStatus, name,
emailId);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{jobTitle}")
.buildAndExpand(app.getOffer().getJobTitle()).toUri();
return ResponseEntity.created(location).body(app);
}
And service class is
#Override
public Application createApplicationMultipartFile(MultipartFile file, String jobTitle, String applicationStatus,
String name, String emailId) throws IOException {
if (!offerRepository.existsById(jobTitle)) {
throw new ResourceNotFoundException("JobTitle " + jobTitle + " not found !!");
}
List<String> emailIds = new ArrayList<>();
List<Application> appliedApplications = applicationRepository.findByOfferJobTitle(jobTitle);
for (Application app : appliedApplications) {
emailIds.add(app.getEmailId());
}
if (emailIds.contains(emailId)) {
throw new ExistingResourceException("User " + emailId + " has already applied for the given Post !!");
}
Offer offer = offerRepository.findById(jobTitle).get();
Application application = new Application();
application.setApplicationStatus(ApplicationStatus.valueOf(applicationStatus));
application.setResume(file.getBytes());
application.setName(name);
application.setEmailId(emailId);
application.setOffer(offer);
return applicationRepository.save(application);
}
i want to write unit test case for controller. i am using testNg and mockito for this.
below is my understanding
public class ApplicationControllerTest {
private MockMvc mvc;
private JacksonTester<Application> jsonApplication;
#Mock
ApplicationService appService;
#InjectMocks
ApplicationController appController;
private Offer offer;
private Application app1;
List<Application> appList1;
#BeforeMethod
public void setup() {
offer = new Offer("LSE", new Date(),1);
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.standaloneSetup(appController)
.build();
JacksonTester.initFields(this, new ObjectMapper());
}
#Test
public void canCreateANewApplicationMultiPart() throws Exception {
Mockito.when(appService.createApplicationMultipartFile(Mockito.any(MultipartFile.class), Mockito.eq("LSE"), Mockito.any(String.class), Mockito.any(String.class), Mockito.any(String.class))).thenReturn(app1);
MockHttpServletResponse response = mvc.perform(post("/offers/LSE/applications").contentType(MediaType.MULTIPART_FORM_DATA_VALUE)
.content(jsonApplication.write(new Application("john","john123","res".getBytes(),offer,ApplicationStatus.APPLIED)).getJson())).andReturn().getResponse();
assertThat(response.getStatus()).isEqualTo(HttpStatus.CREATED.value());
assertThat(response.getContentAsString()).isEqualTo(new ObjectMapper().writeValueAsString(app1));
}
i guess my controller is expecting inputs in #requestParam thats why i m getting error. if possible give the testcases for this controller method
I'm using Spring Boot in an app that uses REST servers and REST clients. My problem occurs when I let people choose the URL mapping, because then I need to dynamically create a REST Controller with this URL mapping:
#SpringBootApplication
public static void main(String[] args){
SpringApplication.run(MyClass.class);
String urlMapping = "/url/url";
CreateNewRestController c = new CreateNewRestController(urlMapping);
}
#RestController
public class CreateNewRestController{
String url;
public CreateNewRestController(String url){
this.url = url
}
#RequestMapping(value = this.url,method = RequestMethod.GET)
public String getHello(){
return "Hello";
}
}
"Why are you using a url variable when you could use a constant string in the RequestMapping?" you may ask. But this is a simple example and I need to create the RequestMapping using a variable argument.
Github link - here
I found a awnser to my question and maybe a solution to used RequestMapping in real time. I created a RestController that take all the HTTP petitions to it, them the petition ask to a hash map with have the uri mapping like key and a class controller like value.
The generic controller:
#RestController
public class GeneralController {
HashMap<String,PersonalizedController> petitions = new HashMap<String,PersonalizedController>();
#RequestMapping("**")
public ResponseEntity<Object> index(HttpServletRequest request,HttpServletResponse response,#RequestBody Object body) {
// Inicialization zone - this zone don't must exist
petitions.put("/dir/esta1", new PersonalizedController("esta1"));
petitions.put("/dir/esta2", new PersonalizedController("esta2"));
//-------------------------------------------------
return handlePetition(request,response);
}
private ResponseEntity<Object> handlePetition(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
String petition = request.getRequestURI();
String method = request.getMethod();
return petitions.get(petition).makePetition(method,new String());
}
}
The controller class:
public class PersonalizedController {
private String name;
public PersonalizedController(String name) {
this.name = name;
}
public ResponseEntity<Object> makePetition(String method,Object body) {
// TODO Auto-generated method stub
switch (method) {
case "GET":
return doGet(body);
case "POST":
return doPost(body);
case "PUT":
return doPut(body);
case "DELETE":
return doDelete(body);
default:
return new ResponseEntity<Object>("",HttpStatus.METHOD_NOT_ALLOWED);
}
}
public ResponseEntity<Object> doGet(Object body) {
return new ResponseEntity<Object>("["+name+"] GET",HttpStatus.OK);
}
public ResponseEntity<Object> doPost(Object body) {
return new ResponseEntity<Object>("["+name+"] POST",HttpStatus.OK);
}
public ResponseEntity<Object> doDelete(Object body) {
return new ResponseEntity<Object>("["+name+"] DELETE",HttpStatus.OK);
}
public ResponseEntity<Object> doPut(Object body) {
return new ResponseEntity<Object>("["+name+"] PUT",HttpStatus.OK);
}
}
I solved this for my use case by using a Map to store 'sub' paths and passing all the requests to a generalized controller.
My use case needed a generic proxy app for multiple back-ends. Not too much different than what as you described a possible solution.
Source code -
https://github.com/savantly-net/mesh-gateway
Example -
#RestController
#RequestMapping(MeshGateway.PATH)
public class MeshGateway {
protected static final String PATH = "/gateway";
private static final Logger log = LoggerFactory.getLogger(MeshGateway.class);
private MeshGatewayConfig config;
public MeshGateway(MeshGatewayConfig config) {
this.config = config;
}
#GetMapping("/{child}/**")
public ResponseEntity<?> get(#PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).get();
}
#PostMapping("/{child}/**")
public ResponseEntity<?> post(#PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).post();
}
#PutMapping("/{child}/**")
public ResponseEntity<?> put(#PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).put();
}
#RequestMapping(path = "/{child}/**", method = RequestMethod.OPTIONS)
public ResponseEntity<?> options(#PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).options();
}
#RequestMapping(path = "/{child}/**", method = RequestMethod.PATCH)
public ResponseEntity<?> patch(#PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).patch();
}
#RequestMapping(path = "/{child}/**", method = RequestMethod.DELETE)
public ResponseEntity<?> delete(#PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).delete();
}
#RequestMapping(path = "/{child}/**", method = RequestMethod.HEAD)
public ResponseEntity<?> head(#PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).head();
}
private String getDestinationPath(String child, ProxyExchange<byte[]> proxy) {
String destination = this.config.getRoutes().get(child);
String path = proxy.path(String.format("%s/%s", PATH, child));
log.debug("with prefix removed: {}", path);
return String.format("%s%s", destination, path);
}
}
Let's say I would like to validate incoming ID parameter for all my RESTful methods (>50).
As an example I have:
#RequestMapping(
value = "/{id}",
method = RequestMethod.GET,
produces = {"application/json"})
#ResponseStatus(HttpStatus.OK)
public
#ResponseBody
Metadata getMetadata(
#PathVariable("id") Long id,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
return metadataService.get(id);
}
I would like to reject all requests if id < 1. As a solution I've implemented:
#RequestMapping(
value = "/{id}",
method = RequestMethod.GET,
produces = {"application/json"})
#ResponseStatus(HttpStatus.OK)
public
#ResponseBody
Metadata getMetadata(
#Valid Id id,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
return metadataService.get(id.asLong());
}
public class Id {
#Min(1)
#NotNull
private Long id;
public void setId(Long id) {
this.id = id;
}
public Long asLong() {
return id;
}
}
But now I have to implicitly put #Valid annotation for each and every method for Id argument, which seems quite redundant . Is there a way to tell Spring that if there's an Id object as an incoming parameter it should always be #Valid. Without putting annotation each time?
Thanks.
So I've ended up with solution like this:
public class CustomModelAttributeMethodProcessor extends ModelAttributeMethodProcessor {
public CustomModelAttributeMethodProcessor(boolean annotationNotRequired) {
super(annotationNotRequired);
}
#Override
protected void bindRequestParameters(final WebDataBinder binder, final NativeWebRequest request) {
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
((ServletRequestDataBinder) binder).bind(servletRequest);
}
#Override
protected void validateIfApplicable(final WebDataBinder binder, final MethodParameter parameter) {
if (binder.getTarget().getClass().equals(Id.class)) {
binder.validate();
return;
}
super.validateIfApplicable(binder, parameter);
}
}
And configuration:
#Configuration
#EnableWebMvc
public class ApplicationConfig extends WebMvcConfigurerAdapter {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
super.addArgumentResolvers(argumentResolvers);
argumentResolvers.add(new CustomModelAttributeMethodProcessor(true));
}
}
A bit overhead to check class of each and every incoming parameter, but works as expected. Now #Valid annotation can be omitted as validation performs by custom processor.
My Spring controller looks like this:
#Controller
#RequestMapping(value = "calc")
public class CalcController {
protected final Log logger = LogFactory.getLog(getClass());
#Autowired
private MyService myService;
#RequestMapping(method = RequestMethod.GET)
public String showCalcPage(
#ModelAttribute("myModel") MyModel myModel,
Model model, HttpServletRequest request) {
// assemble page
return "calc";
}
#RequestMapping(method = RequestMethod.POST)
public String showResultsPage(
#ModelAttribute("myModel") MyModel myModel,
BindingResult result, Model model,
final RedirectAttributes redirectAttributes,
HttpServletRequest request) {
myService.evaluate(myModel);
redirectAttributes.addFlashAttribute("myModel", myModel);
model.addAttribute("myModel", myModel);
return "redirect:calc/results";
}
#RequestMapping(value = "/results")
public String showResultsPage(ModelMap model,
#ModelAttribute("myModel") final MyModel myModel,
final BindingResult bindingResult) {
// assemble page
return "results";
}
}
I have a mapping of the URL calc with both GET and POST and another for calc/results.
This works perfectly for me but whenever I try to access calc/results directly, the page still renders.
Hence I did a POST restriction to its RequestMethod like:
#RequestMapping(value = "/results", method = RequestMethod.POST)
public String showResultsPage(ModelMap model,
#ModelAttribute("myModel") final MyModel myModel,
final BindingResult bindingResult) {
// assemble page
return "results";
}
This eliminated the direct viewing of the mapping by throwing a 405 but when I submit my form from calc, the error still persists.
How do I merge these two situations that I have?
I actually just want two controllers like the one below to implement POST and page restriction but it's not working in my part (I diagnosed it to the different mapping of jsp).
#Controller
#RequestMapping(value = "calc")
public class CalcController {
protected final Log logger = LogFactory.getLog(getClass());
#Autowired
private MyService myService;
#RequestMapping(method = RequestMethod.GET)
public String showCalcPage(
#ModelAttribute("myModel") MyModel myModel,
Model model, HttpServletRequest request) {
// assemble page
return "calc";
}
#RequestMapping(value = "/results", method = RequestMethod.POST)
public String showResultsPage(
#ModelAttribute("myModel") MyModel myModel,
BindingResult result, Model model,
final RedirectAttributes redirectAttributes,
HttpServletRequest request) {
// assemble page
myService.evaluate(myModel);
model.addAttribute("myModel", myModel);
return "redirect:results";
}
}
I finally implemented both POST restriction and successful viewing of the calc/results page (but without redirect since it causes a "redirect loop" according to my Tomcat server).
Here is the final controller:
#Controller
public class CalcController {
protected final Log logger = LogFactory.getLog(getClass());
#Autowired
private MyService myService;
#RequestMapping(value = "calc", method = RequestMethod.GET)
public String showCalcPage(
#ModelAttribute("myModel") MyModel myModel,
Model model, HttpServletRequest request) {
// assemble page
return "calc";
}
#RequestMapping(value = "calc/results")
public String showResultsPage(
#ModelAttribute("myModel") MyModel myModel,
ModelMap model, final BindingResult bindingResult,
HttpServletRequest request) {
// assemble page
// apply BindingResult validation in da fyoochoor
myService.evaluate(myModel);
model.addAttribute("myModel", myModel);
return "results";
}
}
Visiting calc/results directly now throws an HTTP 500 and that will keep it secured. Just make sure to declare a page for this exception in your web.xml for aesthetics upon deployment.
Currently i am using paging on my page which uses MultiActionController which displays a jsp page perfectly , on the same page now i want to validate a simple textfield (input/form:input) also want to retrieve name and id from a dropdown(Select option) once a link is clicked. Simple !!
Two questions
Can i use a class implements Validator? and inject it same way as simpleformcontroller in config or some other way within the controller? How? example please?
Can i use java bean in jsp -> i always get error of binding, how to indicated controller to use this bean? i have have passed as argument to my method add and also tried overriding newCommandObject
Controller.java
public ModelAndView add(HttpServletRequest request, HttpServletResponse response, Person person) throws Exception {
return new ModelAndView("userpage");
}
#Override
protected Object newCommandObject(Class clazz)
throws Exception {
return new Person();
}
I will do something like below in Spring version > 2.5
#Controller
public class YourController
{
protected final Log logger = LogFactory.getLog(getClass());
private final String yourInputJsp = "yourInputJsp";
private final String yourInputJspSuccess = "yourInputJspSuccess";
private YourService yourService;
#Autowired
#Qualifier("yourFormValidator")
private YourFormValidator validator;
#RequestMapping(value = "/yourRequest.htm", method = RequestMethod.GET)
public String referenceData(ModelMap model, HttpServletRequest request) throws Exception
{
yourService = new YourServiceImpl(ContextHandler.getWebAppContext(request));
YourFormData yourFormData = new YourFormData();
model.addAttribute("yourFormData", yourFormData);
return yourInputJsp;
}
#InitBinder()
public void initBinder(WebDataBinder binder) throws Exception {
binder.registerCustomEditor(String.class, new StringMultipartFileEditor());
}
#RequestMapping(value="/yourRequest.htm", method = RequestMethod.POST)
public String process(#ModelAttribute("yourFormData") YourFormData yourFormData, BindingResult result, SessionStatus status, HttpServletRequest request)
{
String mav = yourInputJsp;
validator.validate(yourFormData, result);
if(!result.hasErrors())
{
//Some business logic
mav = "redirect:yourInputJspSuccess.htm";
status.setComplete();
}
return mav;
}
}