I am currently writing a Spring Boot REST API and wanted to do a reverse resolution of a URL that is defined in a GetMapping. In the Django web framework there is a method for doing that: reverse. But I was not able to find anything like that for Spring Boot.
I am looking for something like this:
package help.me.stack.overflow;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("api")
public class SomeController {
#GetMapping(value = "/items/{filter}/blob")
public ResponseEntity<?> getItems(#PathVariable String filter, #RequestParam String sorting) {
return ResponseEntity.ok().body("here you go");
}
#GetMapping(value = "/give-me-url")
public ResponseEntity<?> getTheUrl() {
return resolveUrl(SomeController.getItems, "foo-filter", "foo-sorting");
// should produce "api/items/foo-filter/blob?sorting=foo-sorting"
}
}
Does something like that exist? How can I use it?
Yup, you can use WebMvcLinkBuilder.linkTo(...) from Spring HATEOAS:
linkTo(methodOn(SomeController.class).getItems("foo-filter", "foo-sorting")).withSelfRel()
See here for more examples
Related
I have a HTML page that is launched from a java controller after a post and I want to attach a query string value in the url ex: (localhost:8000/gdata?id=11). Can this be done? Here is my controller code:
package com.sa.example;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
//import org.springframework.web.bind.annotation.RequestParam;
import com.sentinel.advisor.GData;
import com.sentinel.advisor.GDataJdbcRepository;
#Controller
public class GDataController {
#Autowired
GDataJdbcRepository repository;
#GetMapping("/gdata")
public String gDataForm(Model model) {
return "gData";
}
#PostMapping("/gdata")
public String gDataSubmit(#ModelAttribute GData gData) {
String returnString = repository.insert(gData);
//returnString should be returned in the url as a query string
return "result";
}
}
You can use a redirect (it is best practice to redirect after post regardless see - https://en.wikipedia.org/wiki/Post/Redirect/Get.
Spring's redirect view:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/view/RedirectView.html
Something like:
#Controller
public class GDataController {
#Autowired
GDataJdbcRepository repository;
#GetMapping("/gdata")
public String gDataForm(Model model) {
return "gData";
}
#PostMapping("/gdata")
public RedirectView gDataSubmit(#ModelAttribute GData gData) {
String returnString = repository.insert(gData);
return new RedirectView("/sucess?returnString=" + returnString, true);
}
#GetMapping("/success")
public String getResultPage(#RequestParam("returnString")String returnString){
return "result";
}
}
I have an application with two packages. In the first package, I have 2 controllers. The first controller is called APIController.java which displays a view. This is the code of the controller:
package com.dogo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
#RequestMapping()
public class APIController {
#RequestMapping("/api")
public String apiChat() {
return "apiChat.html";
}
}
The second controller is called HomeController.java which I use to display the index.html page. This is the code:
package com.dogo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class HomeController {
#RequestMapping("/")
public String index() {
return "index.html";
}
}
The second package also contains a controller called MessageController.java. This is used to update a dao database based on the parameters passed in the url. This is the code for this controller:
package com.dogo.chat;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping()
public class MessageController {
#Autowired
MessageRepository dao;
#GetMapping("/chat")
public List<Message> getMessages(){
List<Message> foundMessages = dao.findAll();
return foundMessages;
}
#PostMapping("/chat")
public ResponseEntity<Message> postMessage(#RequestBody Message message)
{
// Saving to DB using an instance of the repo Interface.
Message createdMessage = dao.save(message);
// RespEntity crafts response to include correct status codes.
return ResponseEntity.ok(createdMessage);
}
#GetMapping("/chat/{id}")
public ResponseEntity<Message> getMessage(#PathVariable(value="id")
Integer id){
Message foundMessage = dao.findOne(id);
if(foundMessage == null) {
return ResponseEntity.notFound().header("Message","Nothing found with that id").build();
}
return ResponseEntity.ok(foundMessage);
}
#DeleteMapping("/message/{id}")
public ResponseEntity<Message> deleteMessage(#PathVariable(value="id") Integer id){
Message foundMessage = dao.findOne(id);
if(foundMessage == null) {
return ResponseEntity.notFound().header("Message","Nothing found with that id").build();
}else {
dao.delete(foundMessage);
}
return ResponseEntity.ok().build();
}
}
When I type http://localhost:8080/api into my browser, the apiChat.html page is displayed. When I change the #RequestMapping() in APIController.java to #RequestMapping("/api") and I type http://localhost:8080/api/api I get a 404 error. I had expected the apiChat.html page to be displayed. What am I missing? Thank you.
I have a Spring Boot project using Jersey as my REST service and using AngularJS for my front end development. While I run it without using any controller and go to index.html (which is in resource/static/index.html) it works fine. When I add a controller it renders gives the string "index.html" as an output. Spring Boot Configuration:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan(basePackages = {"com.cst.interfaces","com.cst.configuration","com.cst.application","com.cst.application.implmentation"})
#EnableAutoConfiguration
public class ApplicationConfiguration {
public static void main(String args[]) throws Exception{
SpringApplication.run(ApplicationConfiguration.class, args);
}
public ServletRegistrationBean jerseyServlet(){
ServletRegistrationBean register = new ServletRegistrationBean(new ServletContainer(),"/*");
register.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, JerseyInitalize.class.getName());
return register;
}
}
JerseyConfiguration:
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;
#Component
public class JerseyInitalize extends ResourceConfig{
public JerseyInitalize(){
super();
this.packages("com.cst.interfaces");
}
}
Controller Class:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.springframework.web.bind.annotation.RestController;
#RestController
#Path("/home")
public class HomeResource {
#GET
#Produces("application/json")
public String getString(){
return "index.html";
}
}
This is because you annotated your controller with #RestController, which is a shorthand for #Controller with #ResponseBody. The latter annotation instructs the controller to render the output as-is directly into the response.
Use #Controller for controllers that are not RESTful instead.
I am just getting into spring-cloud-config and I'm working on this basic project. I would like to know if it is possible and how to rewrite this client to not use Spring Boot.
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#EnableAutoConfiguration
#ComponentScan
#RestController
#RefreshScope
public class ClientApp {
#Value("${bar:World!}")
String bar;
#RequestMapping("/")
String hello() {
return "Hello " + bar + "!";
}
public static void main(String[] args) {
SpringApplication.run(ClientApp.class, args);
}
}
The reason for this is that we are thinking of using spring-cloud-config in our spring batch web service, but we use the old spring with xmls, not spring boot. I couldn't find any documentation related to this.
I'm coding a Spring server and I am using Retrofit to make the api calls.
I have the next interface for the Retrofit client:
import retrofit.http.Body;
import retrofit.http.GET;
import retrofit.http.POST;
public interface AuthSvcApi {
public static final String AUTHENTICATION_PATH = "/authToken";
#POST(AUTHENTICATION_PATH)
public boolean loginUser(#Body String accessToken);
}
Then my controller is:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.purposes.client.AuthSvcApi;
#Controller
public class AuthSvc{
#RequestMapping(value=AuthSvcApi.AUTHENTICATION_PATH, method = RequestMethod.POST)
public #ResponseBody boolean loginUser(#RequestBody String accessToken) {
CheckAccessToken checkAccessToken = new CheckFacebookAccessToken();
checkAccessToken.checkToken(accessToken);
return false;
}
}
The method isn't finished, but it should work. And the application class is:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
//Tell Spring to automatically inject any dependencies that are marked in
//our classes with #Autowired
#EnableAutoConfiguration
//Tell Spring to turn on WebMVC (e.g., it should enable the DispatcherServlet
//so that requests can be routed to our Controllers)
#EnableWebMvc
//Tell Spring to go and scan our controller package (and all sub packages) to
//find any Controllers or other components that are part of our applciation.
//Any class in this package that is annotated with #Controller is going to be
//automatically discovered and connected to the DispatcherServlet.
#ComponentScan
//Tell Spring that this object represents a Configuration for the
//application
#Configuration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I don't know why this doesn't work fine, but I am going crazy because the response is:
No mapping found for HTTP request with URI [/authToken] in DispatcherServlet with name 'dispatcherServlet'
Looks like you need to include AuthSvcApi.AUTHENTICATION_PATH
to this line:
.setEndpoint(SERVER).build()
Like this:
.setEndpoint(SERVER + AuthSvcApi.AUTHENTICATION_PATH).build()
Well, I found the solution, the problem was that the annotation #ComponentScan didn't find the package where the controller was. I resolve the problem indicating to the annotation the package where the controller is.
#ComponentScan(basePackages={"com.purposes.controllers"})