I'm working on a Spring project with Gradle, I use mysql-connector-java v-8.0.30, javax.persistence-api v-2.2, and spring-boot-starter-data-jpa dependencies. My project was running correctly, but from one moment to another it stopped compiling, only the Spring logo appears in the console with the following warning: RN 19232 --- [ restartedMain] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
What I thought at first is that the application was not compiling, however when I access it, I execute a class method annotated with #RestController and I paint a message in the HTMl, it is displayed correctly.
#SpringBootApplication
#RestController
public class CompraventaspringApplication {
public static void main(String[] args) {
SpringApplication.run(CompraventaspringApplication.class, args);
}
#GetMapping("/")
public static String message(#RequestParam(value = "saludo", defaultValue =
"i'm a CRUD system") String saludo )
{
return String.format("<h1>Hello %s ! </h1>", saludo);
}
However, when I try to bind any route from a controller to an HTML template the route doesn't map properly. I've already tried to remove the Gradle dependencies and rebuild them but still can't find my HTML:
#Controller
#RequestMapping
public class ControllerProductos {
#Autowired
public ProductoServicesClass service;
public static String UPLOADS = "src/main/resources/static/uploads";
// Listar todos los productos diponibles
#GetMapping("/home")
public String listar(Model model) {
List<Productos> productos = service.listar();
model.addAttribute("productos", productos);
return "HomePage";
}
}
I already checked several times and yes, the name of the template is the same as the one associated with the return of the method.
Related
I have two seperate projects, a projectApi (spring backend) and a projectUi (angular frontent).
I'm using maven-resource-plugin to combine them into one jar for production.
When I start the spring server, the connection between those two modules works fine.
Now I would like to customize the backend url path, so that a request like 'http://localhost:8088/login' looks like 'http://localhost:8088 /api/v1/login'.
I was able to do so, by adding the following entry to application.properties: spring.mvc.servlet-path=/api/v1 and modifying the base url, for calls from the ui to the api.
Since that change I'm getting a whitelabel error calling the ui (localhost:8088).
After some search, I tried to implement WebMvcConfigurer but it did not work for me. This is the reference stackoverflow link.
// Application.java
#SpringBootApplication
#EnableJpaRepositories
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// UserRestService.java
#RestController
#RequestMapping("/user")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class UserRestService extends AbstractRestService {
...
#PostMapping("/login")
public String login(#RequestBody User user) throws CustomException {
return Response.ok(userService.loginUser(user, response));
}
}
// application.properties
server.port=8088
// without that entry the post request works fine -> localhost:8088/user/login
// adding that entry and trying to call: localhost:8088/api/v1/user/login i get whitelabel error
spring.mvc.servlet.path=/api/v1
Try to add "/api/v1/" to your controller otherwise all your controllers will be prefixed by that path and you will not be able to provide other versions withing the same application.
I would prefer to program to an interface. This helps in making better use of IOC. Add the URI prefix (/api/v1/) to the interface like below. It will append this prefix to all methods offered by the interface.
// Interface for UserRestService with URI prefix mentioned using Request mapping annotation
#RequestMapping(value = "/api/certs/", produces = { "application/json" },consumes = { "application/json" })
public interface IUserRestService {
String login(User user) throws CustomException;
}
//UserRestService Class
#RestController
#RequestMapping("/user", method = RequestMethod.POST)
public class UserRestService extends AbstractRestService implements IUserRestService{
...
#PostMapping("/login")
public String login(#RequestBody User user) throws CustomException {
return Response.ok(userService.loginUser(user, response));
}
}
I have a cache class that is loading properties from a .properties file before the application startup, in a simple java project. It logs out everything.I need to convert this project to springboot application.
What annotations can i use to achieve the Cache Loading??
Currently I wrote the code like my spring boot app starts with the #postconstruct , since i am not using web.xml for loading servlets.
#RestController
public class ConfigServlet {
#PostConstruct
public void init() {
//business logic
}
}
And this servlet starts up first. So how can i load cache along this??
It is supposed to load the Cache even before this servlet class loads. How can i achieve this concept??
Suppose you have below properties in your application properties. You can load them as below. The properties will be loaded during the application startup.
application.properties
test.a = 10
test.b =20
test1.a = 30
test1.b = 40
#Configuration
#ConfigurationProperties
Class CacheProperties {
Map<String,String> test;
Map<String,String> test1;
public String getTestB() {
return test.get("b");
}
public String getTestA() {
return test.get("a");
}
public String getTest1B() {
return test1.get("b");
}
public String getTest1A() {
return test1.get("a");
}
//setters
}
I'm trying to get a repository into a class annotated with #Service using the #Autowired annotation in a Spring-boot class. However, the repository turns up as a null.
Here's the relevant code:
#Service
public class ImportLicenses {
#Autowired
private LicenseRepository licenseRepository;
public static void main (String[] args) {
ImportLicenses importLicenses = new ImportLicenses();
importLicenses.listFiles("/Users/admin/Licenses/licenses");
}
private void processLicense (Path path) {
try {
count++;
BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class);
FileTime fileTime = attr.lastModifiedTime();
Permission permission = new Permission(readLineByLineJava8(path.toFile().getAbsolutePath()));
LicensePojo licensePojo = new LicensePojo(permission, path);
Optional<License> licenseOptional = licenseRepository.findById(licensePojo.getId());
at which point it gets an NPE since licenceReposity is null.
I am able to access the licenseRepository in a controller class with this constructor
public LicenseController(LicenseRepository licenseRepository,
UserRepository userRepository) {
this.licenseRepository = licenseRepository;
this.userRepository = userRepository;
}
However, since I'm calling the constructor directly in the static main method, this doesn't seem like it's available. What's the best way to get the repository into this class?
Edit: Thanks for the responses. To clarify the question, I'm trying to pull this class into the structure of the existing Spring Boot application, instead of creating a separate one.
Option 1: Create a button or menu selection on the UI, and create a new controller class to run the import. This would be the simplest, but I don't want to necessarily have that on the UI.
Option 2: Code the import class create another Spring Application
#SpringBootApplication
public class ImportLicenses implements ApplicationRunner {
private final Logger logger = LoggerFactory.getLogger(LicenseGenApplication.class);
#SpringBootApplication
public static void main() {
main();
}
public static void main(String[] args) {
SpringApplication.run(ImportLiceneses.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception {
listFiles("/Users/admin//licenses");
}
public void listFiles(String path) {
try {
Files.walk(Paths.get(path))
.filter(ImportLicenses::test)
.forEach(p -> processLicense(p));
} catch (IOException e) {
e.printStackTrace();
}
}
....
}
Option 3 - Create a non-executable jar file from the existing application for use in the new application to avoid duplicating code.
Option 1 is the quickest, I'm not sure if option 2 work, Option 3 I'll take a look at to see if it's do-able.
Your application is a usual Java application. It is not a Spring Boot application.
What should you do? Make a Spring Boot application of it. For instance, create a demo app at https://start.spring.io/, compare your main class to the main class in the demo application, then adjust your main class correspondingly. Also compare your Maven or Gradle config to the config of the demo app and adjust correspondingly.
At least, your application should have an annotation #SpringBootApplication. Also, it should be launched via SpringApplication.run(...). This is a minimum. Depending on what you need, you may want to use #EnableAutoConfiguration and other configuration options.
I'm trying to achieve something like this:
#Controller
public SomeController {
#CustomConfig("var.a")
private String varA;
#CustomConfig("var.b")
private String varB;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String get() {
return varA;
}
}
CustomConfig would be an #Interface class that accepts one value parameter. The reason why we are not using #Value is because this will not come from config file but from API (such as https://getconfig.com/get?key=var.a). So we are going to make HTTP request to inject it.
So far I've only manage to make something work if the varA and varB is inside get() method as parameter, by using below in a class that extends WebMvcConfigurerAdapter:
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
CustomConfigResolver resolver = new CustomConfigResolver();
argumentResolvers.add(resolver);
}
And inside CustomComfigResolver.resolveArgument() we would do the HTTP query, but that's not really what we wanted, we need it to be injected as class variable.
Does anyone have experience in resolving it at class variable level?
Thank you
This could work if you use #Value instead of your own custom annotation. This uses the built in environment:
#Order(Ordered.HIGHEST_PRECEDENCE)
#Configuration
public class TcpIpPropertySourceConfig implements InitializingBean {
#Autowired
private ConfigurableEnvironment env;
#Autowired
private RestTemplate rest;
public void afterPropertiesSet() {
// Call your api using Resttemplate
RemoteProperties props = //Rest Call here;
// Add your source to the environment.
MutablePropertySources sources = env.getPropertySources();
sources.addFirst(new PropertiesPropertySource("customSourceName", props)
}
}
What you are trying to achieve is difficult when you start to consider "unhappy" scenarios. Server down / not reachable. You need to account for all of that in the method above.
I would highly recommend to instead use Spring Cloud Config. Great guide on that is here: https://www.baeldung.com/spring-cloud-configuration
This provides:
- Reloading of your #Value() properties, so no custom annotation needed.
- A more stable server and great Spring integration out of the box.
Best of all, it is easy to apply Retries and Backoffs if the configuration server goes down (see https://stackoverflow.com/a/44203216/2082699). This will make sure your app doesn't just crash when the server is not available.
I am not able to read a property from properties file through Spring Boot. I have a REST service which is working through the browser and Postman both and returning me a valid 200 response with data.
However, I am not able to read a property through this Spring Boot client using #Value annotation and getting following exception.
Exception:
helloWorldUrl = null
Exception in thread "main" java.lang.IllegalArgumentException: URI must not be null
at org.springframework.util.Assert.notNull(Assert.java:115)
at org.springframework.web.util.UriComponentsBuilder.fromUriString(UriComponentsBuilder.java:189)
at org.springframework.web.util.DefaultUriTemplateHandler.initUriComponentsBuilder(DefaultUriTemplateHandler.java:114)
at org.springframework.web.util.DefaultUriTemplateHandler.expandInternal(DefaultUriTemplateHandler.java:103)
at org.springframework.web.util.AbstractUriTemplateHandler.expand(AbstractUriTemplateHandler.java:106)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:612)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:287)
at com.example.HelloWorldClient.main(HelloWorldClient.java:19)
HelloWorldClient.java
public class HelloWorldClient {
#Value("${rest.uri}")
private static String helloWorldUrl;
public static void main(String[] args) {
System.out.println("helloWorldUrl = " + helloWorldUrl);
String message = new RestTemplate().getForObject(helloWorldUrl, String.class);
System.out.println("message = " + message);
}
}
application.properties
rest.uri=http://localhost:8080/hello
There are several problems in your code.
From the samples you posted, it seems that Spring is not even started. The main class should run the context in your main method.
#SpringBootApplication
public class HelloWorldApp {
public static void main(String[] args) {
SpringApplication.run(HelloWorldApp.class, args);
}
}
It isn't possible to inject a value into a static field. You should start with changing it into a regular class field.
The class must be managed by Spring container in order to make value injection available. If you use default component scan you can simply annotate the newly created client class with the #Component annotation.
#Component
public class HelloWorldClient {
// ...
}
If you don't want to annotate the class you can create a bean in one of your configuration classes or your main Spring Boot class.
#SpringBootApplication
public class HelloWorldApp {
// ...
#Bean
public HelloWorldClient helloWorldClient() {
return new HelloWorldClient();
}
}
However, if you are the owner of the class, the first option is preferable. No matter which way you choose, the goal is to make the Spring context aware of class existence so the injection process can happen.