I have spring boot single page web application using angular js, bootstrap for the front end and rest API for the back-end and both front-end and back-end runs on embedded tomcat container of spring boot. I am using spring boot 1.2.7 version
Following code sample shows how I am bootstrap this spring boot application
#Configuration
#SpringBootApplication
#EnableAsync
#EnableScheduling
#ComponentScan(basePackages = { "sg.abc.test.api.config", Constant.BASE_PACKAGE, sg.abc.c4s.util.Constant.BASE_PACKAGE })
#EnableAutoConfiguration(exclude = { JndiConnectionFactoryAutoConfiguration.class, DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, JpaRepositoriesAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class })
#PropertySources({
#PropertySource(value = "classpath:jdbc.properties")
})
public class TestApp extends SpringBootServletInitializer {
private static final Logger logger = LoggerFactory.getLogger(TestApp.class);
#Autowired
InternalSettingService internalSettingService;
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
application.headless(true);
return application.sources(TestApp.class);
}
#Bean
public ModelMapper mapper() {
ModelMapper mapper = new ModelMapper();
mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
return mapper;
}
public static void main(String[] args) {
try {
SpringApplicationBuilder builder = new SpringApplicationBuilder(EmenuApp.class);
builder.headless(false);
context = builder.run(new String[] {});
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(null, "Butterfly eMenu Application already running.");
}
}
This system works without ssl configuration. However when I configure spring boot to have ssl, I am only able to access the rest api, but the web app is not getting loaded into the browser.
Could anybody advice me what could be the reason behind this wired behavior. If u require further explanations please put a comment below, I will provide more details.
It is not self signed certificate.
I got the certificate from godaddy
This is how I configured it
server.ssl.key-store=data/test.keystore
server.ssl.key-store-password=test123
server.ssl.key-password=test123
with this configuration, rest api works fine and responds to https api calls, only the web application is not responding , this is what I see in the browser
Related
I am trying to test functionality in an application that occurs when the app registers with a service registry. This happens only when the app has a full web context (ie. spring-boot-starter-web is on the class path, and the servlet is not mocked). This is controlled via spring-cloud-commons AbstractAutoServiceRegistration.
Simple Test
All the test should do is the following:
1) Bring up Web App
2) Verify auto-registration w/ service registry event fired
3) Manually force close app
4) Verify auto-deregistratoin occurred
Approach 1: #SpringBootTest
SpringBootTest makes it easy to create the full web context, which is great. But I cannot close the app mid-test to force a deregister
#RunWith(SpringRunner.class)
#SpringBootTest(
classes = MyAutoConfig.class,
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT
)
#EnableAutoConfiguration
public class DiscoverySpringCloudBootMinimalRegistrationTest {
#Test
public void register_deregister {
// Force-close app to trigger dereigster (causes exception)
((ConfigurableApplicationContext) context).close();
verify(registry, times(1)).register(autoRegistrationServiceRecord);
verify(registry, times(1)).deregister(autoRegistrationServiceRecord);
}
The context.close() call results in a long error, basically saying not to manually close the context like this.
..... contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]] is not active. This may be due to one of the following reasons: 1) the context was closed programmatically by user code; 2) the context was closed during parallel test execution either according to #DirtiesContext semantics or due to automatic eviction from the ContextCache due to a maximum cache size policy.
Approach 2: WebContextRunner
In this approach, I avoid #SpringBootTest and manually configure a context runner. This works nicely for calling context.close() but the web context in configures has a mock servlet, and DOES NOT trigger the WebInitializedEvent required for autoregistration.
public class BasicAutoConfigTests {
private WebApplicationContextRunner runner;
#Test
public void register_deregister() {
runner = new WebApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(MyAutoConfig.class));
runner.run((context) -> {
assertThat(context).hasNotFailed();
ServiceRegistry registry = context.getBean(ServiceRegistry.class);
ServiceRecord autoRegistration = context.getBean(MyServiceRecord.class);
context.close();
verify(registry, times(1)).register(autoRegistration);
verify(registry, times(1)).deregister(autoRegistration);
});
}
This almost works but results in a MockServletContext bean, which I presume is failing to trigger the requisite WebServerInitializedEvent from spring-cloud-commons. How can this approach bootstrap an authentic, complete embedded tomcat server?
Following Spencer's advice, I used the spring application builder to create a full web app. I also did this outside of the autoconfiguration module - created a new maven submodule called "integration tests" with spring-boot-starter-web on the classpath.
#Import(MyAutoConfig.class)
#SpringBootApplication
public class MinStarterBasicApp {
#Bean
ServiceRegistry serviceRegistry() {
return mock(ServiceRegistry.class);
}
static ConfigurableApplicationContext setupWebApp(String... profiles){
System.setProperty("spring.main.allow-bean-definition-overriding", "true");
SpringApplication app = new SpringApplicationBuilder(MinStarterBasicApp.class)
.web(WebApplicationType.SERVLET)
.profiles(profiles)
.build();
return app.run();
}
}
Where profiles allows me to pass in a application.properties files by name as shown below. Also it's important to make sure we manually close the app context for each test.
public class StarterBasicAutoconfigTest {
ConfigurableApplicationContext context;
#After
public void teardown() {
if (context != null && context.isRunning())
context.close();
}
#Test
public void sometest() {
context = MinStarterBasicApp.setupWebApp("profile1");
ServiceRegistry registry = context.getBean(ServiceRegistry.class);
context.close();
Mockito.verify(registry, times(1)).register(any());
Mockito.verify(registry, times(1)).deregister(any());
}
I've got an issue with calling my microservice.
I run the server, and my microservice registers correctly:
But when I try and call a method in microservice, it fails with UnknownHostException.
This is how my RestTemplate and MsImageService beans are made:
#Configuration
#EnableAsync
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class MvcConfig extends WebMvcConfigurerAdapter {
#Bean
#LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
#Bean
public MsImageService msImageService() {
return new MsImageService("http://IMAGES-MICROSERVICE");
}
}
And this is how I autowire it in my service:
#Autowired
#LoadBalanced
private RestTemplate restTemplate;
These are the properties I use on my server:
server.port=8761
spring.thymeleaf.enabled=false
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.default-zone=http://${eureka.instance.hostname}:${server.port}/eureka/
logging.level.com.netflix.eureka=INFO
logging.level.com.netflix.discovery=INFO
And this is the properties in my service:
spring.application.name=images-microservice
spring.freemarker.enabled=false
spring.thymeleaf.enabled=false
security.basic.enabled=false
eureka.instance.instance-id=${spring.application.name}
eureka.client.service-url.default-zone=http://localhost:8761/eureka/
server.port=2222
logging.level.com.netflix.eureka=INFO
logging.level.com.netflix.discovery=INFO
Any help is appreciated!
Thanks!
From your server properties, try to remove the below line. It makes eureka client inside your server not fetch other servers info from eureka server.
eureka.client.fetch-registry=false
Also check that your Application class of server has #EanbleEurekaClient or #EnableDiscoveryClient annotation. Your server application also must be a Eureka client to fetch others.
From your service properties, remove the below line. Overriding instance-id is not required at all (but, it might not be related to your problem)
eureka.instance.instance-id=${spring.application.name}
If you need a full example, try to check this example code. (Readme.md is written in Korean, but codes are very simple. So there will be no problem to read the code without readme)
I have a project in which i am using Spring mvc 4 and i need to include there apache shiro security. I've tried to search over the web for a solution for my problem but didn't managed to fins something. Although there is a guide at Shiro's web site, but this example is only for xml configured Spring project, and my project doesn't contain any xml at all, and when i am trying to configure Shiro with annotation only it fails.
When i run this project i have an access to all of my end points, and non of them is being restricted by Shiro.
I guess that my configuration is wrong but i am unable to figure out which part of it is wrong.
I am not allowed to use Spring boot (i know that there is examples for that).
here is my configuration class:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.myproject.menu")
public class AppConfiguration extends WebMvcConfigurerAdapter{
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("/");
}
#Bean(name="shiroFilter")
public ShiroFilterFactoryBean shiroFilter (){
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setLoginUrl("/MenuTest/login");
shiroFilter.setFilterChainDefinitions("/MenuTest/init=anon");
shiroFilter.setFilterChainDefinitions("/MenuTest/**=authc");
shiroFilter.setSecurityManager(realm());
return shiroFilter;
}
private DefaultWebSecurityManager realm(){
DefaultWebSecurityManager realm = new DefaultWebSecurityManager();
return realm;
}
}
Thx in advance!
Take a look at the 1.4.0 (RC2) release. There is updated Spring and Spring-Boot support.
And examples in the source tree:
https://github.com/apache/shiro/tree/master/samples/spring-mvc
I have a jax-rs resources which I am trying to convert to spring boot. I have made them work but looks like some of jax-rs resources which are included in project as dependencies from other projects. I know it should be a service! Anyway so I may be able to make change to that library and make them mvc compatible but is there another way I can make spring servlet work with both? I am using all java based configuration btw no xml.
Main application class is currently annotated as following unless I add "/" in url-mapping which moots the point of adding this. I don't even see why I should add this if dispatcher servlet can find handler for every / request.
#SpringBootApplication(exclude = { EmbeddedServletContainerFactory.class })
#EnableAsync
#ImportResource(value = { "classpath:springmvc-resteasy.xml" })
public class Application implements AsyncConfigurer, DisposableBean { .. }
I think with above spring DispatcherServlet is still at front in control and it knows of rest easy handleradapters. By default boot also maps everything under '/' so I dont understand why it doesnt work. I am getting 404 when hitting jax-rs uri, spring mvc uri works.
I tried to add following but after that everything stopped working.
#Bean
public ServletRegistrationBean initServlet(DispatcherServlet dispatcherServlet) {
ServletRegistrationBean servletRegistrationBean
= new ServletRegistrationBean(dispatcherServlet, false,"/jaxrs-api/*", "/mvc-api/*");
servletRegistrationBean
.setName(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
return servletRegistrationBean;
}
I can see following beans are being loaded for resteasy upon context initialization.
resteasy.deployment
resteasy.registry
resteasy.dispatcher
resteasy.providerFactory
resteasy.spring.bean.processor
abstract.resteasy.handlerMapping
resteasy.handlerMapping
resteasy.handlerAdapter
resteasy.exception.handler
resteasy.no.resource.found.view
reateasy.error.view.resolver
It looks like things started working again after some try and errors which is not the way this should be! Spring-boot really should document here how it can work with spring mvc and jax-rs in co-existence.
Here's the sequence of changes I did.
I added #EnableWebMvc to my Application.java class or It can be on any other #Configuration class
#SpringBootApplication(exclude = { EmbeddedServletContainerFactory.class })
#EnableAsync
#EnableWebMvc
#ImportResource(value = { "classpath:springmvc-resteasy.xml" })
public class Application implements AsyncConfigurer, DisposableBean { .. }
In hindsight I knew this gonna create some problem and it did! My additional MessageConverter stopped working. I had following in Application.java
#Bean
public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper scalaObjectMapper = new ScalaObjectMapper();
//scalaObjectMapper.enable(features)
//objectMapper.registerModule(new DefaultScalaModule());
scalaObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
jsonConverter.setObjectMapper(scalaObjectMapper);
return jsonConverter;
}
Now I had to move it to another config class which overrides WebMvcConfigurerAdapter to customize spring mvc beans.
#Component
#Configuration
public class WebMvcCustomConfig extends WebMvcConfigurerAdapter {
/**
* Registering Scala ObjectMapper
* #return
*/
#Bean
public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper scalaObjectMapper = new ScalaObjectMapper();
scalaObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
jsonConverter.setObjectMapper(scalaObjectMapper);
return jsonConverter;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
//converters.add(ScalaObjectMapper);
super.configureMessageConverters(converters);
converters.add(customJackson2HttpMessageConverter());
}
}
So looks like now Spring MVC has some control rather then Spring Boot. I am sure this is gonna break loose when I have some additional components for example swagger2 integration or something similar.
I am working on a web application using SpringBoot.
The problem I am facing is as follows. The application is running fine from Eclipse, but when I deploy the project as a war in tomcat 7, it's giving me "HTTP Status 404". No exception found in tomcat logs.
Below is my controller:
#RestController
public class TinyUrlController{
#Autowired TinyUrlService tinyUrlService;
#RequestMapping("/create")
public String createUrl(#RequestParam("url") String url,HttpServletRequest request){
TinyUrl tinyUrl = tinyUrlService.createUrl(url);
return tinyUrl.toString();
}
}
Seems your application have no entry point that's why you got nothing. Just create entry point into your application.
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(applicationClass, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<Application> applicationClass = Application.class;
}
See also Spring Boot deploying guide
I suggest that you try to build your application layout by using
http://start.spring.io/
It will make a SpringBoot application
It will make java packages right too
Just remember to place your controllers under java package "demo".. otherwise they cannot be "auto wired" without more configuration...
I suggest you make a simple controller that just returns "hello" as a starter...