Spring MVC with RESTful Services and Static HTML - java

I am using Java8 with Spring 4.3.1.RELEASE. I have a project that needs to serve both static html pages and RESTful Services.
I can get one to work at a time, but not both at the same time.
For example, I need to access:
http://localhost:8080/jbosswildfly-1.0/category/list
http://localhost:8080/jbosswildfly-1.0/category/list/{id}
and
http://localhost:8080/jbosswildfly-1.0/index.html
http://localhost:8080/jbosswildfly-1.0/tocs.html
http://localhost:8080/jbosswildfly-1.0/www/index.html
My issue is with regards to my servlet-mapping.
I have the following:
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.setServletContext(servletContext);
Dynamic rest = servletContext.addServlet("rest", new DispatcherServlet(ctx));
//dynamic.addMapping("/**/*.do");
rest.addMapping("/*.html");
rest.addMapping("/category/list");
rest.addMapping("/category/list/*");
rest.setLoadOnStartup(1);
}
}
I have tried a number of combinations of mappings, but cannot seem to get static content and RESTful services to work simultaneously.
In the above example, I can get the following to work:
http://localhost:8080/jbosswildfly-1.0/index.html
http://localhost:8080/jbosswildfly-1.0/snoop.jsp
http://localhost:8080/jbosswildfly-1.0/WebContent/index.html
http://localhost:8080/jbosswildfly-1.0/category/list
But, the following is not found:
http://localhost:8080/jbosswildfly-1.0/category/list/AC
The following allows the RESTful Services to be accessed, but not the static html files:
rest.addMapping("/");
Any help appreciated.
UPDATE
Here is the code for one of my RESTful Services:
#CrossOrigin(origins = {"*"})
#RestController
#RequestMapping(CategoryRESTService.BASE_URI)
public class CategoryRESTService {
public static final String BASE_URI = "/category";
#Autowired
private CategoryService categoryService;
#RequestMapping(value = "/list", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<Category>> findAllCategorys() {
List<Category> categories = categoryService.findAll();
return new ResponseEntity<List<Category>>(categories, HttpStatus.OK);
}
#RequestMapping(value = "/list/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Category> findCategoryById(#PathVariable String id) {
Category category = categoryService.findById(id);
return new ResponseEntity<Category>(category, HttpStatus.OK);
}
}

try to use rest.addMapping("/"); mapping, at the same time you have to configure static resource resolver, for example
through xml configuration
<mvc:resources mapping="*.html" location="location of the resource folder" />
or java-base config
#Configuration
#EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("*.html")
.addResourceLocations("location of the resource folder");
}
}

Related

Getting HttpClientErrorException 404 RestTemplate getForObject

I am trying to make a REST service run that was written by my uni professor, it has the following 3 modules:
A core module containing services, repositories, model classes
A web module containing controllers exposed as RESTful Web Services
A client module containing a console-based ui that accesses the
RESTful Web Services using RestTemplate.
These are my config files in the web module.
WebConfig
#Configuration
#EnableWebMvc
#ComponentScan({"ro.ubb.catalog.web.controller", "ro.ubb.catalog.web.converter"})
public class WebConfig {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.exposedHeaders("Access-Control-Allow-Origin:*")
.allowedOrigins("localhost:8080","localhost:4200")
.allowedMethods("GET", "PUT", "POST", "DELETE");
}
};
}
}
AppLocalConfig
#Configuration
#ComponentScan({"ro.ubb.catalog.core"})
#Import({JPAConfig.class})
#PropertySources({#PropertySource(value = "classpath:local/db.properties"),
})
public class AppLocalConfig {
/**
* Enables placeholders usage with SpEL expressions.
*
* #return
*/
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
and a initializer.
public class Initializer implements WebApplicationInitializer {
public void onStartup(ServletContext container)
throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.scan("ro.ubb.catalog.web.config");
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/api/*");
}
}
In my client module i have the following config file:
#Configuration
#ComponentScan("ro.ubb.catalog.client.ui")
public class ClientConfig {
#Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
The console:
#Component
public class ClientConsole {
#Autowired
private RestTemplate restTemplate;
public void runConsole() {
String url = "http://localhost:8080/api/students";
StudentsDto students = restTemplate.getForObject(url, StudentsDto.class);
System.out.println(students);
StudentDto savedStudent = restTemplate.postForObject(url,
new StudentDto("saved-st", 10),
StudentDto.class);
System.out.println("saved student:");
System.out.println(savedStudent);
savedStudent.setName("update-st");
restTemplate.put(url + "/{id}", savedStudent, savedStudent.getId());
System.out.println("update:");
System.out.println(restTemplate.getForObject(url, StudentsDto.class));
restTemplate.delete(url + "/{id}", savedStudent.getId());
System.out.println("delete:");
System.out.println(restTemplate.getForObject(url, StudentsDto.class));
}
}
And the client main:
public class ClientApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("ro.ubb.catalog.client.config");
ClientConsole console = context.getBean(ClientConsole.class);
console.runConsole();
System.out.println("bye ");
}
}
And lastly this is the controller in the web module:
#RestController
public class StudentController {
#Autowired
private StudentService studentService;
#Autowired
private StudentConverter studentConverter;
#RequestMapping(value = "/students")
StudentsDto getAllStudents() {
return new StudentsDto(
studentConverter.convertModelsToDtos(
studentService.getAllStudents()));
}
#RequestMapping(value = "/students", method = RequestMethod.POST)
StudentDto addStudent(#RequestBody StudentDto studentDto){
var student = studentConverter.convertDtoToModel(studentDto);
var result = studentService.saveStudent(student);
var resultModel = studentConverter.convertModelToDto(result);
return resultModel;
}
#RequestMapping(value = "/students/{id}", method = RequestMethod.PUT)
StudentDto updateStudent(#PathVariable Long id,
#RequestBody StudentDto dto) {
return
studentConverter.convertModelToDto(
studentService.updateStudent(
studentConverter.convertDtoToModel(dto)
));
}
#RequestMapping(value = "/students/{id}", method = RequestMethod.DELETE)
ResponseEntity<?> deleteStudent(#PathVariable Long id) {
studentService.deleteStudent(id);
return new ResponseEntity<>(HttpStatus.OK);
}
}
First I am wondering if maybe I configured the server wrong, I installed tomcat and added to the webapps folder the jar file of the root project module. The server seems to be running, so I am not entirely sure if that is the problem. I created a table with entities, still the same error.
I am not familiar with the code as I am trying first to get it to work and then practice around with it so I understand how everything works.
This is the entire stack trace
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.springframework.cglib.core.ReflectUtils$1 (file:/C:/Users/aytre/.gradle/caches/modules-2/files-2.1/org.springframework/spring-core/5.0.3.RELEASE/8950eb10c466a77677693dd495d4b6a26de315f4/spring-core-5.0.3.RELEASE.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of org.springframework.cglib.core.ReflectUtils$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Exception in thread "main" org.springframework.web.client.HttpClientErrorException: 404 null
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:94)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:79)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:773)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:726)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:682)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:330)
at ro.ubb.catalog.client.ui.ClientConsole.runConsole(ClientConsole.java:17)
at ro.ubb.catalog.client.ClientApp.main(ClientApp.java:15)

AnjularJs integration with Spring boot

I need to call index() method in java class. But I tried this way it is not working.
It is going up to console.log('coming here....'); in controller.js, after that http path is not recognizing.
#RestController
public class DatumBoxShedule {
#Autowired
private DatumService datumService;
#RequestMapping(value = "/loadIndex", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public String index() throws IOException {
}
}
controller.js
app.controller('datumBoxShedule', function($scope, $http) {
$scope.newTodo = {};
$scope.loadIndex = function(){
console.log('coming here....');
$http.get('loadIndex')
.success(function(data, status, headers, config) {
$scope.todos = data;
})
.error(function(data, status, headers, config) {
alert('Error loading DatumBoxShedule');
});
};
$scope.loadIndex();
});
Is the Angular project part of the Spring project?
Are other mappings working (in other words: is the REST-Service running)?
If not: do you have an embedded container like Tomcat in your depenedencies?
For example, you could add the dependency for Tomcat to your project:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
I figureout ,issue is not in the anujularjs.Issue is in the spring.
my componantscan is not working
package main.java.datumbox;
#Configuration
#SpringBootApplication
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
#ComponentScan({"main.java.datumbox.service.impl","main.java.datumbox.controller","main.java.datumbox.service"})
public class Application{
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class,args);
}
}
package main.java.datumbox.service.impl;
public class DatumServiceImpl{
#Autowired(required = true)
DatumDataRepository datumDataRepository;
}
package main.java.datumbox.controller;
#RestController
public class DatumBoxController {
#Autowired
private DatumService datumService;
#Autowired
private DatumServiceImpl datumServiceImpl;
#RequestMapping( value = "/loadIndex" , produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public String index() throws IOException {
}
}
package main.java.datumbox.service;
#Service
public class DatumService{
#Autowired
HitApiService hitApiService;
}
error is coming..
APPLICATION FAILED TO START
Description:
Field datumServiceImpl in main.java.datumbox.controller.DatumBoxController required a bean of type 'main.java.datumbox.service.impl.DatumServiceImpl' that could not be found.
Action:
Consider defining a bean of type 'main.java.datumbox.service.impl.DatumServiceImpl' in your configuration.

How to register a JavaEE filter in your Spring Boot application?

I have the following Spring Boot controller and a JavaEE filter classes in my Spring Boot based REST application. Please note that I do not have a web.xml configured here.
http://localhost:8080/api/products -> Returns 200
The problem is that the interceptor/filter never gets called.
ProductController.java
#RestController
#RequestMapping("/api")
public class ProductController {
#Inject
private ProductService productService;
//URI: http://localhost:8080/api/products
#RequestMapping(value = "/products", method = RequestMethod.GET)
public ResponseEntity<Iterable<Product>> getAllProducts() {
Iterable<Product> products = productService.getAllProducts();
return new ResponseEntity<>(products, HttpStatus.OK);
}
//URI: http://localhost:8080/api/products/50
#RequestMapping(value = "/products/{productId}", method = RequestMethod.GET)
public ResponseEntity<?> getProduct(#PathVariable Long productId) {
Product product = productService.getProduct(productId);
return new ResponseEntity<>(product, HttpStatus.OK);
}
}
SecurityFilter.java
#WebFilter(urlPatterns = {"/api/products/*"})
public class SecurityFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
//in the init method
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//THIS METHOD NEVER GETS CALLED AND HENCE THIS NEVER GETS PRINTED ON CONSOLE.
//WHY ?????
System.out.println("**********Into the doFilter() method...........");
final HttpServletRequest httpRequest = (HttpServletRequest) request;
final HttpServletResponse httpResponse = (HttpServletResponse) response;
//move ahead
chain.doFilter(httpRequest, httpResponse);
}
#Override
public void destroy() {
//nothing to implement
}
}
BasicRestApplication.java
#SpringBootApplication
public class BasicRestApplication {
public static void main(String[] args) {
SpringApplication.run(BasicRestApplication.class, args);
}
}
I have gone through this link How to add a filter class in Spring Boot? but it does not give a clear idea on what needs to be added where to register the filter with Spring Boot.
Found the solution from here Add a Servlet Filter in a Spring Boot application
Created a new configuration class and registered the filter class.
#Configuration
public class ApplicationConfig {
#Bean
public Filter securityFilter() {
return new SecurityFilter();
}
}

Project starting in embedded Tomcat, but doesn't work in full Tomcat

I have small SpringBoot project with few RESTful-services which I made for studying Spring and REST technology. If I run it through spring-boot:run it working properly on localhost:8080/ + what I wrote in #RequestMapping in Controller. In example, on localhost:8080/restapp/test/{id} :
#RequestMapping(value = "http ://localhost:8080/restapps-0.0.1-SNAPSHOT/restapp/test/{id}",
method = RequestMethod.GET)
public String getWelcome(#PathVariable(value = "id") String id) {
return "Welcome to jax-rs " + id;
}
While deploying in full Tomcat, it started on localhost:8080/project_version it opened index.html (whitch I added for testing while created project) and i haven't access to my services. I trying:
localhost:8080/project_version/restapp/test/{id}
localhost:8080/project_version/test/{id}
localhost:8080/project_version/project_name/restapp/test/{id}
but have only 404 error.
Application.java
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
Controller.java
#RestController
public class Controller extends ApplicationConfig {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(Controller.class);
return s;
}
#RequestMapping(value = "http ://localhost:8080/restapps-0.0.1-SNAPSHOT/restapp/test/{id}",
method = RequestMethod.GET)
public String getWelcome(#PathVariable(value = "id") String id) {
return "Welcome to jax-rs " + id;
}
}
ApplicationConfig - empty class, which extends Application.
Thanx for all advises/answers.
Your controller mapping is NOT correct because Controller #RequestMapping value should be only the relative path, not the absolute path, so it needs to be changed as shown below:
#RestController
#RequestMapping(value="/test")
public class Controller extends ApplicationConfig {
#RequestMapping(value = "{id}", method = RequestMethod.GET)
public String getWelcome(#PathVariable(value = "id") String id) {
return "Welcome to jax-rs " + id;
}
}
You should be able to access your Controller method using the below url (for resource id 1):
http ://localhost:8080/restapps-0.0.1-SNAPSHOT/test/1
Try to add #SpringBootApplication or #EnableWebMvc in Application class.
Then see javaguy's answer.
Problem was solved by extending Application from SpringBootServletInitializer.

Why do I get 404 for rest with spring-boot

I am implementing rest services with Spring Boot. The entity classes are defined in a separate package. So I added that with Component annotation in Application.java.
#Configuration
#EnableAutoConfiguration
#ComponentScan("org.mdacc.rists.cghub.model")
#EnableJpaRepositories(basePackages = "org.mdacc.rists.cghub.model")
public class Application
{
public static void main( String[] args )
{
SpringApplication.run(Application.class, args);
}
}
Here is my controller class:
// SeqController.java
#RestController
public class SeqController {
#Autowired
private SeqService seqService;
#RequestMapping(
value = "/api/seqs",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<SeqTb>> getSeqs() {
List<SeqTb> seqs = seqService.findAll();
return new ResponseEntity<List<SeqTb>>(seqs, HttpStatus.OK);
}
}
I also created a JPA data repository that extends JPARepository in which I added custom query code.
// SeqRepository.java
#Repository
public interface SeqRepository extends JpaRepository<SeqTb, Integer> {
#Override
public List<SeqTb> findAll();
#Query("SELECT s FROM SeqTb s where s.analysisId = :analysisId")
public SeqTb findByAnalysisId(String analysisId);
}
Below is the servicebean class that implements a service interface
// SeqServiceBean.java
#Service
public class SeqServiceBean implements SeqService {
#Autowired
private SeqRepository seqRepository;
#Override
public List<SeqTb> findAll() {
List<SeqTb> seqs = seqRepository.findAll();
return seqs;
}
public SeqTb findByAnalysisId(String analysisId) {
SeqTb seq = seqRepository.findByAnalysisId(analysisId);
return seq;
}
}
When I started the application and type the following url in the browser "http://localhost:8080/api/seqs" , I got 404 error. What did I miss?
Edit #1:
I decided to take out the JPA repository stuff and change the controller class to the following:
#RestController
//#RequestMapping("/")
public class SeqController {
private static BigInteger nextId;
private static Map<BigInteger, Greeting> greetingMap;
private static Greeting save(Greeting greeting) {
if(greetingMap == null) {
greetingMap = new HashMap<BigInteger, Greeting>();
nextId = BigInteger.ONE;
}
greeting.setId(nextId);
nextId = nextId.add(BigInteger.ONE);
greetingMap.put(greeting.getId(), greeting);
return greeting;
}
static {
Greeting g1 = new Greeting();
g1.setText("Hello World!");
save(g1);
Greeting g2 = new Greeting();
g1.setText("Hola Mundo!");
save(g2);
}
#RequestMapping(
value = "/api/greetings",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Collection<Greeting>> getGreetings() {
Collection<Greeting> greetings = greetingMap.values();
return new ResponseEntity<Collection<Greeting>>(greetings, HttpStatus.OK);
}
}
When I started the application and put "localhost:8080/api/greetings" in my browser I still got 404.
==>Did you make sure that your Spring Boot application class and your Rest Controller are in the same base package? For Example if your package for Spring Boot application class is com.example.demo, then your Rest Controller should be in same base package as com.example.demo.controller.
==>I think that is the reason boot is unable to map to the uri of your rest controller. Because #SpringBootApplication has #ComponentScan and #Configuration embedded in it already. Try doing this. I hope it works.
If spring boot starter web is not there in your pom.xml then add the same as the reason could be the code not being able to map the endpoints.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
The first thing I would try is to put #RequestMapping("/") on the class definition of the controller. Keep the same value on the method.
Another thing, unrelated to your problem, is that you do not need to define that custom query. JPA is actually smart enough to do the query you defined just by using that method name. Check out the findByLastName example here: https://spring.io/guides/gs/accessing-data-jpa/.

Categories