How to show downloaded html file in spring-boot application - html

I have a spring-boot application and I want to show pages which was saved in database as zip archive. It looks like on my screen. Many thanks for tips

You can use WebMvcConfigurer with overrided method addResourceHandlers(ResourceHandlerRegistry registry):
#Configuration
#EnableScheduling
public class WebConfig implements WebMvcConfigurer
where you can add folder with your data:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("**/your_folder/**").addResourceLocations("file:"+ "your_base_directory_where your_folder placed");
}
Now you can open this page used by url
http://localhost:8787/your_base_directory_where your_folder placed/maybe_another_folder/your_folder/index.html
You can add new folders in your_base_directory in runtime and load it in your application.

Related

inject model data into spring webflow in cas

I am upgrading a CAS 4 to a CAS 6. I have done several Spring Boot 2 apps, so I know what I am doing there. I can even do some webflow, but only from scratch.
The documentation clearly states not to mess with the base webflow xml, and to "inject" your own services.
How does one "inject" a service? I really just need to add a message of the day to the login page.
Does anyone have an example of something this simple?
Find below my approach, tested on a cas-maven-overlay installation with cas version at 5.3.x. Some things maybe different on cas 6 branch but I assume the main idea remains.
First, we should create an Action class that will be injected in the login flow and will add the desired message in the flow scope in order to be available at the template(view).
public class DailyMessageAction extends AbstractAction{
#Override
protected Event doExecute(RequestContext context) throws Exception {
context.getFlowScope().asMap().put("dailyMessage", "YOUR_AWESOME_MESSAGE");
return success();
}
}
Then create a WebflowConfigurer class and inject our newly created DailyMessageAction in the actions list(see doInitialize method).
public class DailyMessageWebflowConfigurer extends AbstractCasWebflowConfigurer{
final Action dailyMessageAction;
public DailyMessageWebflowConfigurer(FlowBuilderServices flowBuilderServices,
FlowDefinitionRegistry flowDefinitionRegistry,
ApplicationContext applicationContext,
CasConfigurationProperties casProperties,Action dailyMessageAction){
super(flowBuilderServices, flowDefinitionRegistry, applicationContext, casProperties);
this.dailyMessageAction = dailyMessageAction;
}
#Override
protected void doInitialize() {
final Flow flow = super.getLoginFlow();
flow.getStartActionList().add(dailyMessageAction);
}
}
After that we should inject DailyMessageWebflowConfigurer in cas runtime. This is achieved by creating a configuration class and inject our configurer.
#Configuration
public class CustomWebflowConfiguration {
#Autowired
private CasConfigurationProperties casProperties;
#Autowired
#Qualifier("loginFlowRegistry")
private FlowDefinitionRegistry loginFlowDefinitionRegistry;
#Autowired
private ApplicationContext applicationContext;
#Autowired
private FlowBuilderServices flowBuilderServices;
#RefreshScope
#ConditionalOnMissingBean(name = "dailyMessageAction")
#Bean
public Action dailyMessageAction(){
return new DailyMessageAction();
}
#ConditionalOnMissingBean(name = "dailyMessageWebflowConfigurer")
#Bean
#RefreshScope
public CasWebflowConfigurer dailyMessageWebflowConfigurer(){
final DailyMessageWebflowConfigurer w = new DailyMessageWebflowConfigurer(flowBuilderServices,
loginFlowDefinitionRegistry,
applicationContext,
casProperties,
dailyMessageAction());
w.initialize();
return w;
}
}
Include our CustomWebflowConfigurationclass in META-INF/spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=your_package.CustomWebflowConfiguration
The final step is to present the added message in the view. Achieved by adding this line
<div th:utext="${dailyMessage}"></div>
in the templates/casLoginView.html file.
... add a message of the day to the login page...
Modifying the spring webflow directly is not recommended in CAS. read this for more info
So if I were you instead of tinkering with spring webflow, I would try to do something like the following:
Note:
Bare in mind this might not be the recommended way to do so, but I think this will work, and much less work than overriding spring webflow
As you said you are quite familiar with Spring boot, so I won't bored you with detail implementation, I can follow up if you / other reader are confused
If your message of the day can be hard coded, just skip 1-3 and go straight with 4.
Ok here we go:
Override the CasSupportActionsConfiguration, only adding the initialFlowSetupAction bean
Adding a custom class (let named it MyInitialFlowSetupAction) and implement the InitialFlowSetupAction
In MyInitialFlowSetupAction, add something like this:
#Override
public Event doExecute(final RequestContext context) {
Event returnEvent = super.doExecute(context);
configureMyAwesomeMessageOfTheDay(context)
return returnEvent;
}
private void configureMyAwesomeMessageOfTheDay(final RequestContext context) {
String messageOfTheDay = "Spring is the best season!";//Your logic here
context.getFlowScope().put("MESSAGE_OF_THE_DAY", messageOfTheDay);
}
4 . CAS 6 is using WAR overlay, so you can overlay the html file, including this one
https://github.com/apereo/cas/blob/v6.0.3/webapp/resources/templates/casLoginView.html
overlay that file, and add your MESSAGE_OF_THE_DAY to it
<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}">
...
<body class="login">
<main role="main" class="container mt-3 mb-3">
Message of the day is: ${MESSAGE_OF_THE_DAY}
...
</main>
</body>
</html>
See if this helps you

How to run jul-to-slf4j bridge once per JVM?

I'd like to run Surefire in parallel mode (multiple JVMs) where each JVM must run:
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
exactly once before the first test. How can this be done?
There are various ways to make some code run at the beginning of a test suite.
Here are 4 (I'm sure there are more):
JUnit via RunWith Suite with Suite.SuiteClasses and BeforeClass (adapted from examples in SuiteTest):
#RunWith(Suite.class)
#SuiteClasses({FirstTest.class, SecondTest.class/*, ...*/, LastTest.class})
public static class AllWithSLF4JBridgeHandler {
#BeforeClass
public static void registerRootLoggerHandlers() {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
}
TestNG with BeforeSuite:
/**
* Base class for each test class (i.e. every test class should extend this class).
*/
public abstract class BaseTest {
#BeforeSuite
public void registerRootLoggerHandlers() {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
}
TestNG with Guice:
/**
* Test module. Each test class should be annotated with `#Guice(TestModule.class)`.
*/
public class TestModule implements Module {
#Override
public void configure(Binder binder) {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
}
Static initialization blocks (test-framework independent):
/**
* Base class for each test class (i.e. every test class should extend this class).
*/
public abstract class BaseTest {
static {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
}
I'm not sure how all of these methods work with Surefire's parallel mode. Methods 1 and 2 may not work there but I believe methods 3 and 4 should.
Another option would be to not use the programmatic installation of the SLF4JBridgeHandler but to use a java.util.logging.config file or class (see LogManager):
"java.util.logging.config.file":
logging.properties file:
// register SLF4JBridgeHandler as handler for the j.u.l. root logger
handlers = org.slf4j.bridge.SLF4JBridgeHandler
System property assignment:
java -Djava.util.logging.config.file=/path/to/logging.properties ...
This works well if you know the path to your logging file beforehand.
"java.util.logging.config.class":
Using a file may not be a good option if you're deploying a WAR and don't know where the file will be, etc. so alternatively you can create a logging config class:
public class SLF4JBridgeHandlerInitializer {
public SLF4JBridgeHandlerInitializer() throws IOException {
String loggingConfigurationString = "handlers = " + SLF4JBridgeHandler.class.getName();
InputStream inputStream = new ByteArrayInputStream(loggingConfigurationString.getBytes());
LogManager.getLogManager().readConfiguration(inputStream);
}
}
System property assignment:
java -Djava.util.logging.config.class=package.SLF4JBridgeHandlerInitializer ...
I've done this before and it has worked well for me (SLF4JBridgeHandler.Initializer by mfulton26 · Pull Request #57 · qos-ch/slf4j).
These final two options should initialize each JVM instance as long as the appropriate system property is set.

Unable to access HTML files from spring MVC

I am writing basic spring mvc application which have no xml configuration its annotation based. I am trying to access html files like
" localhost:9090/help.html " but i get error
No mapping found for HTTP request with URI [/help.html] in DispatcherServlet with name 'dispatcher'
here is my config
#EnableWebMvc
#Configuration
#ComponentScan({ "com.example.test" })
public class WebConfig extends WebMvcConfigurationSupport {
#Bean
public InternalResourceViewResolver internalResourceViewResolver(){
InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
internalResourceViewResolver.setViewClass(JstlView.class);
internalResourceViewResolver.setPrefix("/jsp/");
internalResourceViewResolver.setSuffix(".jsp");
return internalResourceViewResolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/*");
registry.addResourceHandler("/**/*").addResourceLocations("/templates/*");
}
}
my html pages are inside
webapp->templates
i have tried many question here but none helped and all of them relates to xml config
any suggestions ??
Ok I figured this out. It was just a silly mistake. In addResourceLocations i removed * at the end and bingo issued resolved
so this is wrong
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/*");
correct form is
registry.addResourceHandler("/resources/**").addResourceLocations("/resources");
Now i can access html pages directly like
localhost:8080/resources/help.html
even this is possible now
localhost:8080/help.html
because i have added another resource-handler as addResourceHandler("/*\*/**")

Nancy on ASP.NET vNext does not load the Nancy.Viewengines.Razor viewengine

I am trying Nancy with ASP.NET vNext on debian. I've setup a sample project and got it to work with a self hosted Owin application.
Nancy it self seem to run fine but it is looking for the views in the K runtime directory and the Razor viewengine won't load.
K does not show the Nancy.Viewengines.Razor being loaded altho it is in the project.json file
This is the error that I'm getting:
Nancy.RequestExecutionException: Oh noes! ---> Nancy.ViewEngines.ViewNotFoundException: Unable to locate view 'ViewTest'
Currently available view engine extensions: sshtml,html,htm
Locations inspected: views/Home/ViewTest-nl-NL,views/Home/ViewTest,Home/ViewTest-nl-NL,Home/ViewTest,views/ViewTest-nl-NL,views/ViewTest,ViewTest-nl-NL,ViewTest
Root path: /home/vnext/.kre/packages/KRE-mono45-x86.1.0.0-alpha3/bin/
If you were expecting raw data back, make sure you set the 'Accept'-header of the request to correct format, for example 'application/json' at Nancy.ViewEngines.DefaultViewFactory.GetRenderedView (string,object,Nancy.ViewEngines.ViewLocationContext) <0x008a3>
.
My project.json:
{
"dependencies": {
"Microsoft.Owin.Hosting": "2.1.0-*",
"Microsoft.Owin.Hosting": "2.1.0-*",
"Microsoft.Owin.Host.HttpListener": "2.1.0-*",
"Nancy": "0.23.2-*",
"Nancy.Owin": "0.23.2-*",
"Nancy.Viewengines.Razor": "0.23.2-*",
},
}
Loaded library's:
vnext#vnext:~/test/src$ k run
/home/vnext/.kre/packages/KRE-mono45-x86.1.0.0-alpha3/bin/klr.host.dll Information : 0 : [LoaderContainer]: Load name=Microsoft.Owin.Host.HttpListener
/home/vnext/.kre/packages/KRE-mono45-x86.1.0.0-alpha3/bin/klr.host.dll Information : 0 : [DefaultLoaderEngine]: LoadFile(/home/vnext/.kpm/packages/Microsoft.Owin.Host.HttpListener/2.1.0/lib/net45/Microsoft.Owin.Host.HttpListener.dll)
/home/vnext/.kre/packages/KRE-mono45-x86.1.0.0-alpha3/bin/klr.host.dll Information : 0 : [NuGetAssemblyLoader]: Loaded name=Microsoft.Owin.Host.HttpListener in 1ms
/home/vnext/.kre/packages/KRE-mono45-x86.1.0.0-alpha3/bin/klr.host.dll Information : 0 : [LoaderContainer]: Load name=Nancy.Owin
/home/vnext/.kre/packages/KRE-mono45-x86.1.0.0-alpha3/bin/klr.host.dll Information : 0 : [DefaultLoaderEngine]: LoadFile(/home/vnext/.kpm/packages/Nancy.Owin/0.23.2/lib/net40/Nancy.Owin.dll)
/home/vnext/.kre/packages/KRE-mono45-x86.1.0.0-alpha3/bin/klr.host.dll Information : 0 : [NuGetAssemblyLoader]: Loaded name=Nancy.Owin in 1ms
It will load a normal html view when I place it in the KRE bin directory but not in the project's View folder.
How can I force Nancy to look in the right folder, and how can I load the Razor viewengine?
This is the code that i've used: https://github.com/matthijsbreemans/nancy-owin-vnext
Nancy scans the AppDomain.CurrentDomain.BaseDirectory for assemblies by default. In vNext, the assemblies are stored in separate packages, and not in the bin directory, therefore it cannot find the Razor view engine. Until full support is available you can implement your own bootstrapper and override the ViewEngines list:
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
container.Register<IViewEngine, Nancy.ViewEngines.Razor.RazorViewEngine>();
container.Register<Nancy.ViewEngines.Razor.IRazorConfiguration, Nancy. ViewEngines.Razor.DefaultRazorConfiguration>();
}
protected override IEnumerable<Type> ViewEngines
{
get { return new[] { typeof(Nancy.ViewEngines.Razor.RazorViewEngine) }; }
}
The views are also stored in a different directory (especially when published). Create a new class that implements IRootPathProvider, and return the IApplicationEnvironment.ApplicationBasePath. I've done this (for now as a workaround) by storing the IApplicationEnvironment in a static variable (the IoC in Nancy itself can't find an instance when using it in the bootstrapper):
public class Startup
{
internal static IApplicationEnvironment Environment { get; private set; }
public Startup(IApplicationEnvironment env)
{
Environment = env;
}
public void ConfigureServices(IServiceCollection services) { }
public void Configure(IApplicationBuilder app)
{
app.UseOwin(a => a.UseNancy());
}
}
and implement Nancy's IRootPathProvider:
public class vNextRootPathProvider : IRootPathProvider
{
private string BasePath = Startup.Environment.ApplicationBasePath;
public string GetRootPath()
{
return BasePath;
}
}
KRE can't found the views directory, you can custom the Bootstrapper and override IRootPathProvider , setting the root directory to absolute path. Look at : https://github.com/NancyFx/Nancy/wiki/The-root-path

How to handle RPCs in client-server PlayN game?

I'd like to use PlayN to create a client/server card game, e.g. Hearts. While I'm mostly focusing on the HTML5 output, I'd ideally like to be output-platform-agnostic in case I decide to make an Android client in the future. How should I approach the RPC mechanism?
These are the options I've thought of:
Use JSON for RPCs with get()/post() methods - write a servlet that accepts/returns JSON, and make all versions of client code use that. This seems doable, but I'm concerned about JSON's verbosity. Once I get Hearts working I'd like to move on to more complex games, and I'm worried that JSON will result in a lot of much-larger-than-necessary messages being passed back and forth between client and server. I don't actually know how to work with JSON in Java, but I assume this is doable. Are my assumptions in-line? How well does Java work with JSON?
Continue using GWT-RPC. I can do this by taking an asynchronous service interface in my core (platform-agnostic) constructor, and in my HTML main() I pass in the GWT Async interface generated by GWT.create(MyService.class) (or at least a wrapper around it). I have no idea how well this would work for non-HTML versions though. Is it possible for me to use GWT-RPC from client-side Java code directly?
Use some other form of RPC. Any suggestions?
For the GWT RPC on the Java and Android platforms, I'm currently experimenting with using gwt-syncproxy to provide Java client access to the GWT RPC methods, and I'm using Guice, Gin, and RoboGuice on their respective target platforms to inject the appropriate asynchronous service instances for the instantiated Game object.
In the core/pom.xml for a PlayN project, I include the following dependency coordinates to support DI from Gin/Guice/RoboGuice as needed:
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
Then I add #Inject annotations to any fields inside of the concrete Game implementation:
public class TestGame implements Game {
#Inject
TestServiceAsync _testService;
...
}
In the html/pom.xml, I include the dependency coordinates for Gin:
<dependency>
<groupId>com.google.gwt.inject</groupId>
<artifactId>gin</artifactId>
<version>1.5.0</version>
</dependency>
And I create TestGameGinjector and TestGameModule classes:
TestGameGinjector.java
#GinModules(TestGameModule.class)
public interface TestGameGinjector extends Ginjector {
TestGame getGame();
}
TestGameModule.java
public class TestGameModule extends AbstractGinModule {
#Override
protected void configure() {
}
}
Since at the moment, I'm only injecting the TestServiceAsync interface, I don't need to put any implementation in the TestGameModule.configure() method; Gin manages instantiation of AsyncServices for me via GWT.create().
I then added the following to TestGame.gwt.xml
<inherits name='com.google.gwt.inject.Inject'/>
And finally, I made the following changes to TestGameHtml.java
public class TestGameHtml extends HtmlGame {
private final TestGameGinjector _injector = GWT.create(TestGameGinjector.class);
#Override
public void start() {
HtmlPlatform platform = HtmlPlatform.register();
platform.assetManager().setPathPrefix("test/");
PlayN.run(_injector.getGame());
}
}
And this pretty much covers the HTML5 platform for PlayN.
For the Java platform, I add the following dependency coordinates to java/pom.xml:
<dependency>
<groupId>com.gdevelop.gwt.syncrpc</groupId>
<artifactId>gwt-syncproxy</artifactId>
<version>0.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0-rc2</version>
</dependency>
Do note that the gwt-syncproxy project on Google Code does not contain a pom.xml. I have a mavenized version of gwt-syncproxy forked and available via git at https://bitbucket.org/hatboyzero/gwt-syncproxy.git. You should be able to clone it, run mvn clean package install to get it into your local Maven repository.
Anyways, I created a TestGameModule.java for the Java platform as follows:
public class TestGameModule extends AbstractModule {
#Override
protected void configure() {
bind(TestServiceAsync.class).toProvider(TestServiceProvider.class);
}
public static class TestServiceProvider implements Provider<TestServiceAsync> {
public TestServiceAsync get() {
return (TestServiceAsync) SyncProxy.newProxyInstance(
TestServiceAsync.class,
Deployment.gwtWebPath(), // URL to webapp -- http://127.0.0.1:8888/testgame
"test"
);
}
}
}
And I modified TestGameJava.java as follows:
public class TestGameJava {
public static void main(String[] args) {
Injector _injector = Guice.createInjector(new TestGameModule());
JavaPlatform platform = JavaPlatform.register();
platform.assetManager().setPathPrefix("test/images");
PlayN.run(_injector.getInstance(TestGame.class));
}
}
I went through a similar exercise with the Android platform and RoboGuice -- without going into tremendous detail, the relevant changes/snippets are as follows:
pom.xml dependencies
<dependency>
<groupId>com.gdevelop.gwt.syncrpc</groupId>
<artifactId>gwt-syncproxy</artifactId>
<version>0.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.roboguice</groupId>
<artifactId>roboguice</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0-rc2</version>
<classifier>no_aop</classifier>
</dependency>
TestGameApplication.java
public class TestGameApplication extends RoboApplication {
#Override
protected void addApplicationModules(List<Module> modules) {
modules.add(new TestGameModule());
}
}
TestGameModule.java
public class TestGameModule extends AbstractModule {
#Override
protected void configure() {
bind(TestServiceAsync.class).toProvider(TestServiceProvider.class);
}
public static class TestServiceProvider implements Provider<TestServiceAsync> {
public TestServiceAsync get() {
return (TestServiceAsync) SyncProxy.newProxyInstance(
TestServiceAsync.class,
Deployment.gwtWebPath(), // URL to webapp -- http://127.0.0.1:8888/testgame
"test"
);
}
}
}
TestGameActivity.java
public class TestGameActivity extends GameActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
final Injector injector = ((RoboApplication) getApplication()).getInjector();
injector.injectMembers(this);
super.onCreate(savedInstanceState);
}
#Override
public void main(){
platform().assetManager().setPathPrefix("test/images");
final Injector injector = ((RoboApplication) getApplication()).getInjector();
PlayN.run(injector.getInstance(TestGame.class));
}
}
That's a quick and dirty rundown of how I got Gin/Guice/RoboGuice + GWT working in my project, and I have verified that it works on both Java and HTML platforms beautifully.
Anyways, there's the GWT approach to providing RPC calls to multiple PlayN platforms :).