I am building a UI into a JAR for Spring Server. I have a bunch of Angular JS pages. I want to pass in a command line argument to my jar that tells it where the API server is like so:
java -jar application.jar --api=http://ip:9000
So my application.properties file has:
url=${api:http://localhost:9000}
The way I am currently doing is it just having a hardocoded js config file and on each of my .html pages:
<script src="../js/appName/config.angular.js"></script>
Which contains:
var configData = {
url:"http://localhost:9000"
};
And called in each file:
$scope.apiUrl = configData.url;
How do I tap into the applications.properties file that I can override with my JAR command line parameter during runtime vs. the way it has been coded now.
When you pass a value from command line and the same property name is present in properties file then spring boot overrides the value from command line. So to achieve what you want do something like this
In application.properties
#this is default value
app.url=localhost:8080
Create a class to map the properties value or you can use existing class or something else based on your project structure.
#Component
public class Sample {
#Value("${app.url}")
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
Now when your execute a jar with argument --app.url="someserver:9090" the value will be overriden and you can use this value anywhere.
Note it will also work if you try to access the properties value directly in jsp using expression.
Try it, it works. I have used the same thing in my latest project which is a composite microservices and each component need each others url.
[Edit]
Reference : http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Am I getting it right: The client part is delivered by the application? So the part of the last sentence 'during runtime' has more the meaning of 'bootstrap/initial loading', right? One (old school) approach is to provide the entry html (e.g. index.html) through the application (a simple template engine) and provide the needed information with a setter in a JS config object:
// pseudo js code with thymeleaf
<script th:inline="javascript">
/*<![CDATA[*/
myConfig.url = [[${#httpServletRequest.remoteHost}]];
/*]]>*/
</script>
This is just a sample that will only set the remote host name but I think you get the idea.
Side note: I still don't really get why do you have to set this. If the application contains the client code, why do you work with absolute URLs for remote calls? (Disclaimer: I have only experience in Angular(2) and not with AngularJS)
Related
I am uploading user profile image which is uploading and moved to storage/app/upload/images folder but when I am trying to display that image, below given error occurs.
Method App\Image::__toString() must not throw an exception, caught Illuminate\Database\Eloquent\JsonEncodingException
Here is my controller function for displaying
public function userProfile() {
$image = Image::all();
return view('frontend.layouts.Profile',compact('image'));
}
My view in which I am displaying image
#foreach($image as $images)
<img style="width:210px ; height: 230px " src="/storage/app/upload/images/{{$images->image}}" >
#endforeach
Please Upload your image in Public directory and then try to access that, it will work fine
There are three ways of making an image available to a user:
1. As a public asset
Here the image is made available to everyone. For instance your website logo, or landing page image would be accessed by all. So there is a url to the image that is easily accessed by all. These sort of files would go straight to public/img/ folder.
2. As a protected image available only if specific url is requested
Here user specific images would be accessed by specific people. Think of your members' personal photos that you want to make available only to the member herself or to some specific person. In this case you would store the images in storage/app/public and make a symlink using the artisan command php artisan storage:link You can read more on this here. Assuming that you store your files using random names using str_random() you would then generate urls to your image using the asset() helper like: echo asset('storage/X3jf5j5b2j3n.jpg'); Given that the file names are random, it would be hard to access this image by everyone excepting those who have the url generated using the asset() helper.
3. As a protected image made available using Intervention library
In this case you would first check if user is logged in and then dynamically load the image using Intervention via another protected route. So in your web routes you would first have the user authorization using auth middleware:
Route::group(['middleware' => 'auth'], function () {
Route::get('user', 'UserController#userProfile');
Route::get('images/{image}', 'UserController#serveImage'); // this route serves the image only if user is logged in
});
Then once your have installed Intervention library using composer, our UserController would look like:
use Intervention;
class UserController extends Controller
{
public function userProfile()
{
$images = Image::all();
return view('frontend.layouts.Profile', compact('images'));
}
public function serveImage($image)
{
$filename = storage_path('app/images/'.$image);
return Intervention::make($filename)->response();
}
}
You can see that the image is now being served from the storage folder and not public folder. So this method serveImage() is called only when the route defined earlier for it is authorized. Intervention then works its magic to read the image and send it as a http response.
Your view would change one tad bit to accommodate the new route end point that we defined called images. I assume here that you are storing the filename of the image in db by a field named filename:
#foreach($images as $image)
<img style="width:210px ; height: 230px " src="{{ url('/images/'.$image->filename) }}" >
#endforeach
Note: Do bear in mind that the preferred way to serve images is by using method 2 since it is much faster. You can use method 3 sparingly if you really don't want anyone to even stumble upon the files using the urls.
I am using spark as the backend to a project I am working on. I noticed that spark has the ability to serve templated html, using a templating engine such as velocity, freemaker, etc.
However, this isn't quite what I want. Instead of serving an html template, I would like to serve a plaintext file, while still allowing me to insert parameters where needed. For context, I am trying to allow the user to download code examples based on the parameters they have supplied.
Does anything like this exist, or do I need to essentially build the desired file's content and return it as a string?
Example of what I am trying to do
// example.java
public class Example {
public static void main(String [] args) {
System.out.println( {{ param }} );
}
}
So this ^ would be the plain text template that I am attempting to serve... "param" would be passed to the backend via http request, and inserted into the file. Then I would serve the file to the frontend.
So, (as mentioned in the comment :), glad it helped) you can serve this content as HTML page (then you can use template manager) containing only this plaintext content only. Only exception will be the extension which will be .html instead of .java if the user saves the file.
You could declare a route whose return type is 'text/plain'
get(Main.API_PUBLIC + "/sourcecode", (req, res) -> {
res.status(200);
res.type("text/plain");
return " /* This will be the code snippet you'll be returning */ ";
});
Another alternative would be putting your source code files into the static files directory and link to them in your html.
Cross-posted on the MiniProfiler community.
I'm trying to throw MiniProfiler into my current stack. I think I'm mostly setup, but am missing the UI approach and would like recommendations on the best way to proceed.
Current Stack
SQL for DB (including MiniProfiler tables)
EF 6
WebAPI 2 API app
Angular 1.x. app for the UI (separate app, no MVC backing it) -- I think it's 1.5.x at this point.
So, the current method of RenderIncludes() isn't available to me.
What's the best method to include the JS files and set them up to retrieve the information from the SQL Server storage? I know that the files are included in the UI repo, but I didn't see docs for explicit configuration.
What I've Tried So Far -- Web API App
Installed the MiniProfiler and MiniProfiler.EF6 packages.
Web.Config -- Added Handler
(not sure if this is necessary):
<add name="MiniProfiler" path="mini-profiler-resources/*" verb="*" type="System.Web.Routing.UrlRoutingModule" resourceType="Unspecified" preCondition="integratedMode" />
Added a CORS filter to expose the MiniProfiler IDs to my client app:
public class AddMiniProfilerCORSHeaderFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
actionExecutedContext.Response.Headers.Add("Access-Control-Expose-Headers", "X-MiniProfiler-Ids");
}
}
Add that filter as part of startup:
config.Filters.Add(new AddMiniProfilerCORSHeaderFilter());`
In Global.asax, added to Application_Start():
var connectionString = ConfigurationReader.GetConnectionString(Constants.ConfigSettings.CONNECTION_STRING_NAME);
MiniProfiler.Settings.Storage = new SqlServerStorage(connectionString);
MiniProfilerEF6.Initialize();
Update the begin/end requests:
protected void Application_BeginRequest()
{
if (Request.IsLocal || ConfigurationReader.GetAppSetting(Constants.ConfigSettings.USE_PROFILER, false))
{
var sessionId = Guid.NewGuid().ToString();
MiniProfiler.Start(sessionId);
}
}
protected void Application_EndRequest()
{
MiniProfiler.Stop();
}
What I've tried so far -- client (Angular) App
Snagged the UI files from the Github Repo
Copied the UI directory to my project's output
Reference the CSS:
<link rel="stylesheet" href="js/lib/miniprofiler/includes.css" />
Call the JavaScript
<script async type="text/javascript"
id="mini-profiler"
src="js/lib/miniprofiler/includes.js?v=1.0.0.0"
data-current-id=""
data-path="https://localhost:44378/api/profiler/"
data-children="true"
data-ids=""
data-version="1.0.0.0"
data-controls="true"
data-start-hidden="false"
data-trivial-milliseconds="5">
</script>
Current Status
When I do these things, it looks like it just can't find the appropriate WebAPI controller to render the result. If I can figure out where that controller is or replicate it (as I'm attempting to do currently) I think I'll be in business.
The RenderIncludes function results in a <script> tag being output to the page. It is defined in the UI Repo as include.partial.html and currently looks like this:
<script async type="text/javascript" id="mini-profiler"
src="{path}includes.js?v={version}" data-version="{version}"
data-path="{path}" data-current-id="{currentId}"
data-ids="{ids}" data-position="{position}"
data-trivial="{showTrivial}" data-children="{showChildren}"
data-max-traces="{maxTracesToShow}" data-controls="{showControls}"
data-authorized="{authorized}" data-toggle-shortcut="{toggleShortcut}"
data-start-hidden="{startHidden}" data-trivial-milliseconds="{trivialMilliseconds}">
</script>
This is the piece of Javascript that runs the rendering.
The RenderIncludes function is defined here. It does the following:
Makes sure that you have storage set up
Checks that current request is authorized to view results
Gets the Ids of the unviewed profiles for the current user
Takes the Ids along with any other params that you passed into the function and inserts them into the placeholders in the script defined in include.partial.html
Outputs this <script>
So if you cannot call RenderIncludes, there should be no reason why you cannot just put the script file in place, retrieve the unviewed Ids, but them along with any other setup values you want into the <script> tag, and output the tag.
The key lines of code for retrieving the Id values are:
var ids = authorized
? MiniProfiler.Settings.Storage.GetUnviewedIds(profiler.User)
: new List<Guid>();
ids.Add(profiler.Id);
where profiler is the current instance of MiniProfiler (run on the current request.
You will also probably need to make sure that you can handle the call that the script will make to /mini-profiler-resources/results (passing in the id of the profiler as a param). The guts of this is located here in the GetSingleProfilerResult(HttpContext context) function
I have an Angular.js application, and, because it is a single page application, I'm loading some scripts dynamically, depending on the user navigation, so I don't get an overload.
The problem is, some of these scripts are uglified and minified in a ASP.NET MVC Bundle, and when I update a source script, the imported bundle never gets updated.
Why that happens, and what can I do to force an update?
Why that happens
The ASP.NET bundle comes with a caching mechanism. When you add the bundle to the page using Scripts.Render, the engine automatically puts a v query string into the bundle URL.
#Scripts.Render("~/bundles/commands")
produces something like:
<script src="/bundles/commands?v=eiR2xO-xX5H5Jbn3dKjSxW7hNCH9DfgZHqGApCP3ARM1"></script>
If this parameter is not provided, the cached result will be returned. If you add the script tag manually, without it, you can face the same caching issue.
Info about the v query string is provided here ("Bundle Caching"), but is not very helpful.
What can I do
You can still load the bundled scripts dynamically, but you will have to add the v parameter. Note that it doesn't work if you try a randomly generated hash (I tried). Thanks to Frison B Alexander, this is possible using this approach:
private static string GetHashByBundlePath(string bundlePath)
{
BundleContext bundleContext = new BundleContext(new HttpContextWrapper(System.Web.HttpContext.Current), BundleTable.Bundles, bundlePath);
Bundle bundle = BundleTable.Bundles.GetBundleFor(bundlePath);
BundleResponse bundleResponse = bundle.GenerateBundleResponse(bundleContext);
Type bundleReflection = bundleResponse.GetType();
MethodInfo method = bundleReflection.GetMethod("GetContentHashCode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
object contentHash = method.Invoke(bundleResponse, null);
return contentHash.ToString();
}
So what you can do is: Return the bundle hash from the ASP.NET view and get it when you need to load the script.
I my application, I created a JS object specific to it:
var appBundles = {
commands: "/bundles/commands?v=eiR2xO-xX5H5Jbn3dKjSxW7hNCH9DfgZHqGApCP3ARM1"
};
Hope this helps!
I had this problem with bundles not updating when I was loading bundles from one MVC app in another MVC app using GTM (sound messed up, but it actually makes sense in the context of multiple MVC apps sharing code between).
What I came up with is what Marcos Lima wrote in his answer, but taken a step further.
I've added a Bundle controller with following code:
public class BundleController : Controller
{
private static string GetHashByBundlePath(string bundlePath)
{
BundleContext bundleContext = new BundleContext(new HttpContextWrapper(System.Web.HttpContext.Current), BundleTable.Bundles, bundlePath);
Bundle bundle = BundleTable.Bundles.GetBundleFor(bundlePath);
BundleResponse bundleResponse = bundle.GenerateBundleResponse(bundleContext);
Type bundleReflection = bundleResponse.GetType();
MethodInfo method = bundleReflection.GetMethod("GetContentHashCode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
object contentHash = method.Invoke(bundleResponse, null);
return contentHash.ToString();
}
public ActionResult Index(string bundleName)
{
string bundlePath = "~/bundles/" + bundleName;
var hash = GetHashByBundlePath(bundlePath);
return RedirectPermanent(bundlePath + "?v=" + hash);
}
}
Then I've added this route:
routes.MapRoute(
name: "Bundle",
url: "Bundle/{bundleName}",
defaults: new { controller = "Bundle", action = "Index" }
);
The end result is that I request the bundles through the controller, but because I do a 301 redirect the Index action is run only once per user and it returns the current version of the bundle and the bundle is then served from browser cache afterwards. When I actually update the bundle I add some query parameter in the request url (in GTM) and all users now get the updated bundle.
Of course, I assume that bundles are placed in ~/bundles/ path, but that should be easy enough to change if yours are placed elsewhere. In fact the route isn't even necessary.
I'm not sure how I should be serving partials from Symfony to Angular.
I was thinking I should set up a route in Symfony, and then have the controller output the file?
I wasn't sure however how to simply output a file from the controller (i.e. no twig stuff, not really rendering anything, etc.) And will this method cache it properly?
For example,if I want angular to download partials/button.html, should I set up a route like:
partials:
pattern: /web/partials/{partial}
defaults: { _controller: AcmeWebBundle:Partials:show, _format: html }
Then, in my controller have,
...
public function showAction() {
return file_get_contents(' ... path to file ...');
}
....
That obviously doesn't work.. I'm not sure how to output just a straight file without going through twig. Or maybe all my partials should just be twig files (just without any twig stuff in them)?
If you wanted to return the contents like that you would need to add the contents of the file to the response body.
use Symfony\Component\HttpFoundation\Response;
...
public function showAction() {
return new Response(file_get_contents(' ... path to file ...'),200);
}
...
But really you should just let your web server serve the file. What I do is put my partials in a sub folder under the web directory:
web/
partials/
img/
js/
css/
Then just call them domain.com/parials/partialFileName.html and because the file exists symfonys rewrites should ignore it by default and just serve the file.
Another method (mentioned here) is to put the files in your bundle's Resources/public folder, then run
php app/console assets:install --symlink
(where web is the actual directory web/)
This will generate symlinks in the web directory pointing to the public directories. So, if you have:
Acme/DemoBundle/Resources/public/partials/myPartial.html
it'll be available at:
http://www.mydomain.com/bundles/acmedemo/partials/myPartial.html