Use of Spring Cache on web methods - spring-mvc

I am supporting a website which was built with Spring MVC (version 5.2.8) and runs on Tomcat (version 8.5.54). I tested Spring Cache on service methods and database methods, and it worked. However, I am unable to get it work on Ajax web methods. The following is my implementation:
#RequestMapping(value="/data", method = {RequestMethod.POST})
#Cacheable(value = "mycache")
public String myMethod(HttpServletRequest request,
HttpServletResponse response,
#RequestParam(value = "id", required = true) Long id) {
String jsonData = (...pull data from database and generates a json string...)
request.setAttribute("data", jsonData );
return "json";
}
}
}
This is the json.jsp:
<%# page language="java" contentType="application/json; charset=utf-8" %>${data}
Anything wrong with this implementation? Can Spring Cache be used on web methods? I did quite online search and was only able to find examples for service methods and database methods.

Related

How to create a WebClient-object in a spring application with oauth2

I'm developing a spring application (client) that is secured with an OAuth2 provider. This application should do some REST calls to another spring application (resource server). For performing the REST calls, I will use spring's WebClient.
I therefore try to create a bean of type WebClient as can be found in several blogs.
#Configuration
public class AppConfig {
#Bean
public WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations,
new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
oauth.setDefaultClientRegistrationId("myprovider");
return WebClient.builder().filter(oauth).build();
}
}
When starting the application, I get the following error:
The following candidates were found but could not be injected:
- Bean method 'clientRegistrationRepository' in 'ReactiveOAuth2ClientAutoConfiguration' not loaded because NoneNestedConditions 1 matched 0 did not; NestedCondition on ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition.ServletApplicationCondition found 'session' scope
Action:
Consider revisiting the entries above or defining a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' in your configuration.
As several websites recommend exactly this code for generating a WebClient instance when using OAuth2 authentication, I'm wondering what I'm doing wrong?
Do you have any suggestions for me?
Thanks.
I got the same issue. I changed the code as provided in the video : https://www.youtube.com/watch?v=1N-xwmoN83w&t=1569s and that worked
#Bean
public WebClient webClient(ClientRegistrationRepository clientRegistrationRepository , OAuth2AuthorizedClientRepository authorizedClientRepository) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServletOAuth2AuthorizedClientExchangeFilterFunction (clientRegistrationRepository , authorizedClientRepository);
return WebClient.builder().apply(oauth.oauth2Configuration()).build();
}
Hope that helps.

WCFclient operation only Async .Net core 2.0

I added wcf services end point in asp.net core 2.0 to connected services and then I try to use that but with client there is only functions which ended with ..async
I don't want to use ...async.But there is no function without .async
What is problem with this?What should I do?
instead of using that
var response = SystemClient.SearchCountriesAsync(....
I want to use that
var response = SystemClient.SearchCountries(...
but it give that error
Error CS1061 'SystemClient' does not contain a definition for 'SearchCountries' and no extension method 'SearchCountries' accepting a first argument of type 'SystemClient' could be found (are you missing a using directive or an assembly reference?)
Your client does not expose synchronous method but that shouldn't be a problem for you.
Instead of asynchronously calling the method just do this:
response = SystemClient.SearchAirportsAsync(credentials, SystemHelperLanguageTypes.English, SystemHelperSearchTypes.CodeSearch, "ist").Result;
This will call the method synchronously as it will block the call. Check John Skeets answer here.
That being said I would recomend you use the async method that is provided. To support that you would have to change the Action signature to this:
public async Task<IActionResullt> Index()
{
SystemClient SystemClient = new SystemClient();
Credential credential = new Credential();
credential.UserName = "username";
credential.UserPassword = "****";
var response1 = await SystemClient.SearchCountriesAsync(credentials, SystemHelperLanguageTypes.English, SystemHelperSearchTypes.CodeSearch, "TR");
var response = await SystemClient.SearchAirportsAsync(credentials, SystemHelperLanguageTypes.English, SystemHelperSearchTypes.CodeSearch, "ist");
//Do whatever you do with those responses
ViewBag.Language = "ar";
return View();
}
There is a way to generate synchronous methods in your .NET core project in Visual Studio 2019.
Wizard that adds WCF web service reference to your .NET core project has an option Generate Synchronous Operations in the third step, Client Options:
Make sure you check it as it is unchecked by default.

spring MVC controller versioning

I have a spring boot application , which have a spring MVC controller. I am trying to version my rest api using Accept header.
The following is how my Controller looks like
RestController
#RequestMapping(value = "/private/")
public class AppleController {
private final AppleService appleService;
public AppleController(AppleService appleService) {
this.appleService = appleService;
}
#GetMapping(value = "apples/{id}", produces = "application/json; v=1.0",
headers = "Accept=application/json; v=1.0")
public ResponseEntity getByappleId(#PathVariable("id") Long appleId) {
System.out.println("version1");
GetByappleIdResponse response = appleService.findByappleId(appleId);
return new ResponseEntity<>(response, HttpStatus.OK);
}
#GetMapping(value = "apples/{id}", produces = "application/json; v=2.0",
headers = "Accept=application/json; v=2.0")
public ResponseEntity getByappleId2(#PathVariable("id") Long appleId) {
System.out.println("version2");
GetByappleIdResponse response = appleService.findByappleId2(appleId);
return new ResponseEntity<>(response, HttpStatus.OK);
}
Irrespective of the version that I am passing in the Accept header when calling the API always "getByappleId" method is called, hence only version 1 response is returned.
Is there anything wrong in my controller ?
There are many options to implement versioning of REST API:
suggested in the comments approach for manually routing your request;
making version as a part of your Accept header value, f.e.:
(headers = "Accept=application/vnd.name.v1+json")
(headers = "Accept=application/vnd.name.v2+json")
making version as a part of your mapping:
#GetMapping("apples/v1/{id})"
#GetMapping("apples/v2/{id})
So you need to decide which way to go. Some useful links:
Versioning a REST API
Best practices for API versioning?
As described in this answer: https://stackoverflow.com/a/34427044/258813 (and mentioned in the comments) Spring does not support routing using the headers like that.
If you want to support routing via a version header, I would recommend a custom routing condition and annotation - certainly if you are building a large API, it will result in less code and a more elegant solution.
You would define some annotation like #ApiVersion(1) that you can add to any method that is also a request mapping and then add the custom routing condition and it will behave correctly.
I have described using custom routing conditions and annotations (based on subdomains - but that could easily be switched to check headers instead) here: http://automateddeveloper.blogspot.co.uk/2014/12/spring-mvc-custom-routing-conditions.html

Auto-start ASP.NET application hosting WebAPI instance

We're having an odd issue with a WebAPI application hosted by another ASP.NET webapp. The WebAPI controllers are all mapped with Ninject but the ASP.NET host site does not use Ninject.
The issue is that any requests to any of the WebAPI controllers fail with a Ninject error and HTTP 500:
"An error occurred when trying to create a controller of type 'MyObjectsController'. Make sure that the controller has a parameterless public constructor."
However, once even a single request to the main webapp is made (such as opening the login page) then the WebAPI calls all work as expected. The WebAPI is registered and initialized as part of the Application_Start global event. The start event is triggered regardless of whether the first request comes in under the WebAPI or the webapp so it's not bypassing the global startup when coming through the WebAPI before the main app. The WebAPI registration is pretty standard stuff:
GlobalConfiguration.Configure(AddressOf WebApiConfig.Register)
And the Register function itself is nothing unusual:
// Web API configuration and services
var cors = new EnableCorsAttribute("*", "*", "*", "X-Pagination");
//To allow cross-origin credentials in Web API
cors.SupportsCredentials = true;
config.EnableCors(cors);
// To disable host-level authentication inside the Web API pipeline and "un-authenticates" the request.
config.SuppressHostPrincipal();
config.Filters.Add(new HostAuthenticationFilter(Startup.OAuthBearerOptions.AuthenticationType));
// Web API routes
var constraintResolver = new DefaultInlineConstraintResolver();
constraintResolver.ConstraintMap.Add("nonzero", typeof(NonZeroConstraint));
//constraintResolver.ConstraintMap.Add("NonEmptyFolderIds", typeof(NonEmptyFolderIdsConstraint));
config.MapHttpAttributeRoutes(constraintResolver);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
The NinjectConfig is also pretty standard:
public static class NinjectConfig
{
/// <summary>
/// THe kernel of Ninject
/// </summary>
public static Lazy<IKernel> CreateKernel = new Lazy<IKernel>(() =>
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
RegisterServices(kernel);
return kernel;
});
private static void RegisterServices(KernelBase kernel)
{
kernel.Bind<IMyObjectRepository>().To<MyObjectRepository>().InRequestScope();
...
}
}
An example of the DI usage (again, very basic and standard) is:
public class MyObjectRepository : IMyObjectRepository
{
private readonly IMyOtherObjectRepository _objectRepository;
...
public MyObjectRepository(IMyOtherObjectRepository objectRepository)
{
_objectRepository = objectRepository;
...
}
...
}
We want to avoid the requirement of the initial request to the webapp before the WebAPI is available for requests but nothing seems to be getting us towards a solution.
We initially tried out the IIS preloading/app initialization by setting Start Mode to AlwaysRunning and Start automatically to True in the AppPool config. We also enabled preloadEnabled to true and then added the applicationInitialization config section to the web.config such as the following:
<system.webServer>
...
<applicationInitialization>
<add initializationPage="login.aspx" />
</applicationInitialization>
...
</system.webServer>
However, none of these changes and variations of made any difference to the behavior of the WebAPI. We've scoured the web for more help but are at somewhat of a loss as pretty much everything we've come across points to setting the Start Mode, Start Automatically, preloadEnabled, and applicationInitialization and then it will magically work but that's definitely not our experience.
Does anyone have suggestions or ideas?
Install Ninject integration for WebApi nuget package. It creates a file which initializes Ninject on startup. Here is the doc.

How to specify credentials from a Java Web Service in PTC Windchill PDMLink

I am currently investigating the possibility of using a Java Web Service (as described by the Info*Engine documentation of Windchill) in order to retrieve information regarding parts. I am using Windchill version 10.1.
I have successfully deployed a web service, which I consume in a .Net application. Calls which do not try to access Windchill information complete successfully. However, when trying to retrieve part information, I get a wt.method.AuthenticationException.
Here is the code that runs within the webService (The web service method simply calls this method)
public static String GetOnePart(String partNumber) throws WTException
{
WTPart part=null;
RemoteMethodServer server = RemoteMethodServer.getDefault();
server.setUserName("theUsername");
server.setPassword("thePassword");
try {
QuerySpec qspec= new QuerySpec(WTPart.class);
qspec.appendWhere(new SearchCondition(WTPart.class,WTPart.NUMBER,SearchCondition.LIKE,partNumber),new int[]{0,1});
// This fails.
QueryResult qr=PersistenceHelper.manager.find((StatementSpec)qspec);
while(qr.hasMoreElements())
{
part=(WTPart) qr.nextElement();
partName = part.getName();
}
} catch (AuthenticationException e) {
// Exception caught here.
partName = e.toString();
}
return partName;
}
This code works in a command line application deployed on the server, but fails with a wt.method.AuthenticationException when performed from within the web service. I feel it fails because the use of RemoteMethodServer is not what I should be doing since the web service is within the MethodServer.
Anyhow, if anyone knows how to do this, it would be awesome.
A bonus question would be how to log from within the web service, and how to configure this logging.
Thank you.
You don't need to authenticate on the server side with this code
RemoteMethodServer server = RemoteMethodServer.getDefault();
server.setUserName("theUsername");
server.setPassword("thePassword");
If you have followed the documentation (windchill help center), your web service should be something annotated with #WebServices and #WebMethod(operationName="getOnePart") and inherit com.ptc.jws.servlet.JaxWsService
Also you have to take care to the policy used during deployment.
The default ant script is configured with
security.policy=userNameAuthSymmetricKeys
So you need to manage it when you consume your ws with .Net.
For logging events, you just need to call the log4j logger instantiated by default with $log.debug("Hello")
You can't pre-authenticate server side.
You can write the auth into your client tho. Not sure what the .Net equivilent is, but this works for Java clients:
private static final String USERNAME = "admin";
private static final String PASSWORD = "password";
static {
java.net.Authenticator.setDefault(new java.net.Authenticator() {
#Override
protected java.net.PasswordAuthentication getPasswordAuthentication() {
return new java.net.PasswordAuthentication(USERNAME, PASSWORD.toCharArray());
}
});
}

Resources