JAVA-3538: Move spring-rest-testing into spring-web-modules
This commit is contained in:
+25
@@ -0,0 +1,25 @@
|
||||
package com.baeldung.exceptiontesting;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* Main Application Class - uses Spring Boot. Just run this as a normal Java
|
||||
* class to run up a Jetty Server (on http://localhost:8082/spring-rest-full)
|
||||
*
|
||||
*/
|
||||
@EnableScheduling
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan("com.baeldung.exceptiontesting")
|
||||
@SpringBootApplication
|
||||
public class ExceptionTestingApplication extends SpringBootServletInitializer {
|
||||
|
||||
public static void main(final String[] args) {
|
||||
SpringApplication.run(ExceptionTestingApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.baeldung.exceptiontesting.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.baeldung.exceptiontesting.exception.BadArgumentsException;
|
||||
import com.baeldung.exceptiontesting.exception.InternalException;
|
||||
import com.baeldung.exceptiontesting.exception.ResourceNotFoundException;
|
||||
|
||||
@RestController
|
||||
public class ExceptionController {
|
||||
|
||||
@GetMapping("/exception/{exception_id}")
|
||||
public void getSpecificException(@PathVariable("exception_id") String pException) {
|
||||
if("not_found".equals(pException)) {
|
||||
throw new ResourceNotFoundException("resource not found");
|
||||
}
|
||||
else if("bad_arguments".equals(pException)) {
|
||||
throw new BadArgumentsException("bad arguments");
|
||||
}
|
||||
else {
|
||||
throw new InternalException("internal error");
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/exception/throw")
|
||||
public void getException() throws Exception {
|
||||
throw new Exception("error");
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.exceptiontesting.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public class BadArgumentsException extends RuntimeException {
|
||||
|
||||
public BadArgumentsException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.exceptiontesting.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public class InternalException extends RuntimeException {
|
||||
|
||||
public InternalException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.exceptiontesting.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
public class ResourceNotFoundException extends RuntimeException {
|
||||
|
||||
public ResourceNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.baeldung.persistence;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
public interface IOperations<T extends Serializable> {
|
||||
|
||||
// read - one
|
||||
|
||||
T findOne(final long id);
|
||||
|
||||
// read - all
|
||||
|
||||
List<T> findAll();
|
||||
|
||||
// write
|
||||
|
||||
T create(final T entity);
|
||||
|
||||
T update(final T entity);
|
||||
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.baeldung.persistence.dao;
|
||||
|
||||
import com.baeldung.persistence.model.Foo;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
public interface IFooDao extends JpaRepository<Foo, Long> {
|
||||
|
||||
@Query("SELECT f FROM Foo f WHERE LOWER(f.name) = LOWER(:name)")
|
||||
Foo retrieveByName(@Param("name") String name);
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package com.baeldung.persistence.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Foo implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
public Foo() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Foo(final String name) {
|
||||
super();
|
||||
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final Foo other = (Foo) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("Foo [name=").append(name).append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
package com.baeldung.persistence.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
private String email;
|
||||
|
||||
private int age;
|
||||
|
||||
public User() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(final String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(final String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(final String username) {
|
||||
email = username;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(final int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((email == null) ? 0 : email.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final User user = (User) obj;
|
||||
return email.equals(user.email);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("User [firstName=").append(firstName).append("]").append("[lastName=").append(lastName).append("]").append("[username").append(email).append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.baeldung.persistence.service;
|
||||
|
||||
import com.baeldung.persistence.model.Foo;
|
||||
import com.baeldung.persistence.IOperations;
|
||||
|
||||
public interface IFooService extends IOperations<Foo> {
|
||||
|
||||
Foo retrieveByName(String name);
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.baeldung.persistence.service.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import com.baeldung.persistence.IOperations;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@Transactional
|
||||
public abstract class AbstractService<T extends Serializable> implements IOperations<T> {
|
||||
|
||||
// read - one
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public T findOne(final long id) {
|
||||
return getDao().findById(id).orElse(null);
|
||||
}
|
||||
|
||||
// read - all
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<T> findAll() {
|
||||
return Lists.newArrayList(getDao().findAll());
|
||||
}
|
||||
|
||||
// write
|
||||
|
||||
@Override
|
||||
public T create(final T entity) {
|
||||
return getDao().save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T update(final T entity) {
|
||||
return getDao().save(entity);
|
||||
}
|
||||
|
||||
protected abstract PagingAndSortingRepository<T, Long> getDao();
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.baeldung.persistence.service.impl;
|
||||
|
||||
import com.baeldung.persistence.dao.IFooDao;
|
||||
import com.baeldung.persistence.model.Foo;
|
||||
import com.baeldung.persistence.service.IFooService;
|
||||
import com.baeldung.persistence.service.common.AbstractService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class FooService extends AbstractService<Foo> implements IFooService {
|
||||
|
||||
@Autowired
|
||||
private IFooDao dao;
|
||||
|
||||
public FooService() {
|
||||
super();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
@Override
|
||||
protected PagingAndSortingRepository<Foo, Long> getDao() {
|
||||
return dao;
|
||||
}
|
||||
|
||||
// custom methods
|
||||
|
||||
@Override
|
||||
public Foo retrieveByName(final String name) {
|
||||
return dao.retrieveByName(name);
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.baeldung.spring;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.web.context.request.RequestContextListener;
|
||||
|
||||
/**
|
||||
* Main Application Class - uses Spring Boot. Just run this as a normal Java
|
||||
* class to run up a Jetty Server (on http://localhost:8082/spring-rest-full)
|
||||
*
|
||||
*/
|
||||
@EnableScheduling
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan("com.baeldung")
|
||||
@SpringBootApplication
|
||||
public class Application extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
return application.sources(Application.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext sc) throws ServletException {
|
||||
// Manages the lifecycle of the root application context
|
||||
sc.addListener(new RequestContextListener());
|
||||
}
|
||||
|
||||
public static void main(final String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.baeldung.spring;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@PropertySource({ "classpath:persistence-${envTarget:h2}.properties" })
|
||||
@ComponentScan({ "com.baeldung.persistence" })
|
||||
// @ImportResource("classpath*:springDataPersistenceConfig.xml")
|
||||
@EnableJpaRepositories(basePackages = "com.baeldung.persistence.dao")
|
||||
public class PersistenceConfig {
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
public PersistenceConfig() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
|
||||
em.setDataSource(dataSource());
|
||||
em.setPackagesToScan(new String[] { "com.baeldung.persistence.model" });
|
||||
|
||||
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
|
||||
// vendorAdapter.set
|
||||
em.setJpaVendorAdapter(vendorAdapter);
|
||||
em.setJpaProperties(additionalProperties());
|
||||
|
||||
return em;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
||||
dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
|
||||
dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
|
||||
dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
|
||||
dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
|
||||
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager() {
|
||||
final JpaTransactionManager transactionManager = new JpaTransactionManager();
|
||||
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
|
||||
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
|
||||
return new PersistenceExceptionTranslationPostProcessor();
|
||||
}
|
||||
|
||||
final Properties additionalProperties() {
|
||||
final Properties hibernateProperties = new Properties();
|
||||
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
|
||||
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
|
||||
// hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", "true");
|
||||
return hibernateProperties;
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.baeldung.spring;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.ViewResolver;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.view.InternalResourceViewResolver;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("com.baeldung.web")
|
||||
@EnableWebMvc
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
public WebConfig() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ViewResolver viewResolver() {
|
||||
final InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
|
||||
viewResolver.setPrefix("/WEB-INF/view/");
|
||||
viewResolver.setSuffix(".jsp");
|
||||
return viewResolver;
|
||||
}
|
||||
|
||||
// API
|
||||
@Override
|
||||
public void addViewControllers(final ViewControllerRegistry registry) {
|
||||
registry.addViewController("/graph.html");
|
||||
registry.addViewController("/homepage.html");
|
||||
}
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package com.baeldung.web.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.baeldung.persistence.model.Foo;
|
||||
import com.baeldung.persistence.service.IFooService;
|
||||
import com.baeldung.web.util.RestPreconditions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
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 org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/auth/foos")
|
||||
public class FooController {
|
||||
|
||||
@Autowired
|
||||
private IFooService service;
|
||||
|
||||
public FooController() {
|
||||
super();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/count")
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public long count() {
|
||||
return 2l;
|
||||
}
|
||||
|
||||
// read - one
|
||||
|
||||
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Foo findById(@PathVariable("id") final Long id, final HttpServletResponse response) {
|
||||
final Foo resourceById = RestPreconditions.checkFound(service.findOne(id));
|
||||
|
||||
return resourceById;
|
||||
}
|
||||
|
||||
// read - all
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public List<Foo> findAll() {
|
||||
return service.findAll();
|
||||
}
|
||||
|
||||
// write
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@ResponseBody
|
||||
public Foo create(@RequestBody final Foo resource, final HttpServletResponse response) {
|
||||
Preconditions.checkNotNull(resource);
|
||||
final Foo foo = service.create(resource);
|
||||
|
||||
return foo;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.HEAD)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public void head(final HttpServletResponse resp) {
|
||||
resp.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
resp.setHeader("bar", "baz");
|
||||
}
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.web.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/")
|
||||
public class HomeController {
|
||||
|
||||
public String index() {
|
||||
return "homepage";
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.baeldung.web.controller;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.baeldung.web.metric.IActuatorMetricService;
|
||||
import com.baeldung.web.metric.IMetricService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/auth/")
|
||||
public class RootController {
|
||||
|
||||
@Autowired
|
||||
private IMetricService metricService;
|
||||
|
||||
@Autowired
|
||||
private IActuatorMetricService actMetricService;
|
||||
|
||||
public RootController() {
|
||||
super();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
@RequestMapping(value = "/metric", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Map getMetric() {
|
||||
return metricService.getFullMetric();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/status-metric", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Map getStatusMetric() {
|
||||
return metricService.getStatusMetric();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/metric-graph", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Object[][] drawMetric() {
|
||||
final Object[][] result = metricService.getGraphData();
|
||||
for (int i = 1; i < result[0].length; i++) {
|
||||
result[0][i] = result[0][i].toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.web.exception;
|
||||
|
||||
public final class MyResourceNotFoundException extends RuntimeException {
|
||||
|
||||
public MyResourceNotFoundException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public MyResourceNotFoundException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public MyResourceNotFoundException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public MyResourceNotFoundException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package com.baeldung.web.metric;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
|
||||
@Service
|
||||
public class ActuatorMetricService implements IActuatorMetricService {
|
||||
|
||||
@Autowired
|
||||
private MeterRegistry publicMetrics;
|
||||
|
||||
private final List<ArrayList<Integer>> statusMetricsByMinute;
|
||||
private final List<String> statusList;
|
||||
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||
|
||||
public ActuatorMetricService() {
|
||||
super();
|
||||
statusMetricsByMinute = new ArrayList<ArrayList<Integer>>();
|
||||
statusList = new ArrayList<String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[][] getGraphData() {
|
||||
final Date current = new Date();
|
||||
final int colCount = statusList.size() + 1;
|
||||
final int rowCount = statusMetricsByMinute.size() + 1;
|
||||
final Object[][] result = new Object[rowCount][colCount];
|
||||
result[0][0] = "Time";
|
||||
int j = 1;
|
||||
|
||||
for (final String status : statusList) {
|
||||
result[0][j] = status;
|
||||
j++;
|
||||
}
|
||||
|
||||
for (int i = 1; i < rowCount; i++) {
|
||||
result[i][0] = dateFormat.format(new Date(current.getTime() - (60000 * (rowCount - i))));
|
||||
}
|
||||
|
||||
List<Integer> minuteOfStatuses;
|
||||
List<Integer> last = new ArrayList<Integer>();
|
||||
|
||||
for (int i = 1; i < rowCount; i++) {
|
||||
minuteOfStatuses = statusMetricsByMinute.get(i - 1);
|
||||
for (j = 1; j <= minuteOfStatuses.size(); j++) {
|
||||
result[i][j] = minuteOfStatuses.get(j - 1) - (last.size() >= j ? last.get(j - 1) : 0);
|
||||
}
|
||||
while (j < colCount) {
|
||||
result[i][j] = 0;
|
||||
j++;
|
||||
}
|
||||
last = minuteOfStatuses;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Non - API
|
||||
|
||||
@Scheduled(fixedDelay = 60000)
|
||||
private void exportMetrics() {
|
||||
final ArrayList<Integer> lastMinuteStatuses = initializeStatuses(statusList.size());
|
||||
|
||||
for (final Meter counterMetric : publicMetrics.getMeters()) {
|
||||
updateMetrics(counterMetric, lastMinuteStatuses);
|
||||
}
|
||||
|
||||
statusMetricsByMinute.add(lastMinuteStatuses);
|
||||
}
|
||||
|
||||
private ArrayList<Integer> initializeStatuses(final int size) {
|
||||
final ArrayList<Integer> counterList = new ArrayList<Integer>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
counterList.add(0);
|
||||
}
|
||||
return counterList;
|
||||
}
|
||||
|
||||
private void updateMetrics(final Meter counterMetric, final ArrayList<Integer> statusCount) {
|
||||
String status = "";
|
||||
int index = -1;
|
||||
int oldCount = 0;
|
||||
|
||||
if (counterMetric.getId().getName().contains("counter.status.")) {
|
||||
status = counterMetric.getId().getName().substring(15, 18); // example 404, 200
|
||||
appendStatusIfNotExist(status, statusCount);
|
||||
index = statusList.indexOf(status);
|
||||
oldCount = statusCount.get(index) == null ? 0 : statusCount.get(index);
|
||||
statusCount.set(index, (int)((Counter) counterMetric).count() + oldCount);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendStatusIfNotExist(final String status, final ArrayList<Integer> statusCount) {
|
||||
if (!statusList.contains(status)) {
|
||||
statusList.add(status);
|
||||
statusCount.add(0);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package com.baeldung.web.metric;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.search.Search;
|
||||
|
||||
@Service
|
||||
public class CustomActuatorMetricService implements ICustomActuatorMetricService {
|
||||
|
||||
@Autowired
|
||||
private MeterRegistry registry;
|
||||
|
||||
private final List<ArrayList<Integer>> statusMetricsByMinute;
|
||||
private final List<String> statusList;
|
||||
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||
|
||||
public CustomActuatorMetricService() {
|
||||
super();
|
||||
statusMetricsByMinute = new ArrayList<ArrayList<Integer>>();
|
||||
statusList = new ArrayList<String>();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
@Override
|
||||
public void increaseCount(final int status) {
|
||||
String counterName = "counter.status." + status;
|
||||
registry.counter(counterName).increment(1);
|
||||
if (!statusList.contains(counterName)) {
|
||||
statusList.add(counterName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[][] getGraphData() {
|
||||
final Date current = new Date();
|
||||
final int colCount = statusList.size() + 1;
|
||||
final int rowCount = statusMetricsByMinute.size() + 1;
|
||||
final Object[][] result = new Object[rowCount][colCount];
|
||||
result[0][0] = "Time";
|
||||
|
||||
int j = 1;
|
||||
for (final String status : statusList) {
|
||||
result[0][j] = status;
|
||||
j++;
|
||||
}
|
||||
|
||||
for (int i = 1; i < rowCount; i++) {
|
||||
result[i][0] = dateFormat.format(new Date(current.getTime() - (60000 * (rowCount - i))));
|
||||
}
|
||||
|
||||
List<Integer> minuteOfStatuses;
|
||||
for (int i = 1; i < rowCount; i++) {
|
||||
minuteOfStatuses = statusMetricsByMinute.get(i - 1);
|
||||
for (j = 1; j <= minuteOfStatuses.size(); j++) {
|
||||
result[i][j] = minuteOfStatuses.get(j - 1);
|
||||
}
|
||||
while (j < colCount) {
|
||||
result[i][j] = 0;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Non - API
|
||||
|
||||
@Scheduled(fixedDelay = 60000)
|
||||
private void exportMetrics() {
|
||||
final ArrayList<Integer> statusCount = new ArrayList<Integer>();
|
||||
for (final String status : statusList) {
|
||||
Search search = registry.find(status);
|
||||
if (search != null) {
|
||||
Counter counter = search.counter();
|
||||
statusCount.add(counter != null ? ((int) counter.count()) : 0);
|
||||
registry.remove(counter);
|
||||
} else {
|
||||
statusCount.add(0);
|
||||
}
|
||||
}
|
||||
statusMetricsByMinute.add(statusCount);
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package com.baeldung.web.metric;
|
||||
|
||||
public interface IActuatorMetricService {
|
||||
Object[][] getGraphData();
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.baeldung.web.metric;
|
||||
|
||||
public interface ICustomActuatorMetricService {
|
||||
|
||||
void increaseCount(final int status);
|
||||
|
||||
Object[][] getGraphData();
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.web.metric;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface IMetricService {
|
||||
|
||||
void increaseCount(final String request, final int status);
|
||||
|
||||
Map getFullMetric();
|
||||
|
||||
Map getStatusMetric();
|
||||
|
||||
Object[][] getGraphData();
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.baeldung.web.metric;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
@Component
|
||||
public class MetricFilter implements Filter {
|
||||
|
||||
@Autowired
|
||||
private IMetricService metricService;
|
||||
|
||||
@Autowired
|
||||
private ICustomActuatorMetricService actMetricService;
|
||||
|
||||
@Override
|
||||
public void init(final FilterConfig config) throws ServletException {
|
||||
if (metricService == null || actMetricService == null) {
|
||||
metricService = (IMetricService) WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext()).getBean("metricService");
|
||||
actMetricService = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext()).getBean(CustomActuatorMetricService.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws java.io.IOException, ServletException {
|
||||
final HttpServletRequest httpRequest = ((HttpServletRequest) request);
|
||||
final String req = httpRequest.getMethod() + " " + httpRequest.getRequestURI();
|
||||
|
||||
chain.doFilter(request, response);
|
||||
|
||||
final int status = ((HttpServletResponse) response).getStatus();
|
||||
metricService.increaseCount(req, status);
|
||||
actMetricService.increaseCount(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
package com.baeldung.web.metric;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MetricService implements IMetricService {
|
||||
|
||||
private ConcurrentMap<String, ConcurrentHashMap<Integer, Integer>> metricMap;
|
||||
private ConcurrentMap<Integer, Integer> statusMetric;
|
||||
private ConcurrentMap<String, ConcurrentHashMap<Integer, Integer>> timeMap;
|
||||
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||
|
||||
public MetricService() {
|
||||
super();
|
||||
metricMap = new ConcurrentHashMap<String, ConcurrentHashMap<Integer, Integer>>();
|
||||
statusMetric = new ConcurrentHashMap<Integer, Integer>();
|
||||
timeMap = new ConcurrentHashMap<String, ConcurrentHashMap<Integer, Integer>>();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
@Override
|
||||
public void increaseCount(final String request, final int status) {
|
||||
increaseMainMetric(request, status);
|
||||
increaseStatusMetric(status);
|
||||
updateTimeMap(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map getFullMetric() {
|
||||
return metricMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map getStatusMetric() {
|
||||
return statusMetric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[][] getGraphData() {
|
||||
final int colCount = statusMetric.keySet().size() + 1;
|
||||
final Set<Integer> allStatus = statusMetric.keySet();
|
||||
final int rowCount = timeMap.keySet().size() + 1;
|
||||
|
||||
final Object[][] result = new Object[rowCount][colCount];
|
||||
result[0][0] = "Time";
|
||||
|
||||
int j = 1;
|
||||
for (final int status : allStatus) {
|
||||
result[0][j] = status;
|
||||
j++;
|
||||
}
|
||||
int i = 1;
|
||||
ConcurrentMap<Integer, Integer> tempMap;
|
||||
for (final Entry<String, ConcurrentHashMap<Integer, Integer>> entry : timeMap.entrySet()) {
|
||||
result[i][0] = entry.getKey();
|
||||
tempMap = entry.getValue();
|
||||
for (j = 1; j < colCount; j++) {
|
||||
result[i][j] = tempMap.get(result[0][j]);
|
||||
if (result[i][j] == null) {
|
||||
result[i][j] = 0;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// NON-API
|
||||
|
||||
private void increaseMainMetric(final String request, final int status) {
|
||||
ConcurrentHashMap<Integer, Integer> statusMap = metricMap.get(request);
|
||||
if (statusMap == null) {
|
||||
statusMap = new ConcurrentHashMap<Integer, Integer>();
|
||||
}
|
||||
|
||||
Integer count = statusMap.get(status);
|
||||
if (count == null) {
|
||||
count = 1;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
statusMap.put(status, count);
|
||||
metricMap.put(request, statusMap);
|
||||
}
|
||||
|
||||
private void increaseStatusMetric(final int status) {
|
||||
final Integer statusCount = statusMetric.get(status);
|
||||
if (statusCount == null) {
|
||||
statusMetric.put(status, 1);
|
||||
} else {
|
||||
statusMetric.put(status, statusCount + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTimeMap(final int status) {
|
||||
final String time = dateFormat.format(new Date());
|
||||
ConcurrentHashMap<Integer, Integer> statusMap = timeMap.get(time);
|
||||
if (statusMap == null) {
|
||||
statusMap = new ConcurrentHashMap<Integer, Integer>();
|
||||
}
|
||||
|
||||
Integer count = statusMap.get(status);
|
||||
if (count == null) {
|
||||
count = 1;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
statusMap.put(status, count);
|
||||
timeMap.put(time, statusMap);
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.baeldung.web.util;
|
||||
|
||||
import com.baeldung.web.exception.MyResourceNotFoundException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* Simple static methods to be called at the start of your own methods to verify correct arguments and state. If the Precondition fails, an {@link HttpStatus} code is thrown
|
||||
*/
|
||||
public final class RestPreconditions {
|
||||
|
||||
private RestPreconditions() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
/**
|
||||
* Check if some value was found, otherwise throw exception.
|
||||
*
|
||||
* @param expression
|
||||
* has value true if found, otherwise false
|
||||
* @throws MyResourceNotFoundException
|
||||
* if expression is false, means value not found.
|
||||
*/
|
||||
public static void checkFound(final boolean expression) {
|
||||
if (!expression) {
|
||||
throw new MyResourceNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if some value was found, otherwise throw exception.
|
||||
*
|
||||
* @param resource
|
||||
* has value not null to be returned, otherwise throw exception
|
||||
* @throws MyResourceNotFoundException
|
||||
* if resource is null, means value not found.
|
||||
*/
|
||||
public static <T> T checkFound(final T resource) {
|
||||
if (resource == null) {
|
||||
throw new MyResourceNotFoundException();
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user