I just started learning the Spring MVC framework for Java, and I want to learn how to handle CRUD operations as well as handling form data.
So far many tutorials on the net are mostly about Spring with Maven combination which I find confusing as a self-studying beginner.
I would appreciate some clarifications on what I would need exactly to handle CRUD operations in a typical Spring MVC project with a preference of MySQL. Also any relevant tutorial suggestions to get the same would be highly appreciated.
You can perform CRUD operations in Spring very easily with Spring Data JPA.
Suppose you have your entity class YourClass:
#Entity
public class YourClass {
#Id
private Long id;
private String name;
// constructors, getters, setters
}
Just extend your repository interface from org.springframework.data.repository.CrudRepository to have it working.
Note: You can find that org.springframework.data.jpa.repository.JpaRepository is more convenient, feel free to use it because it is also a CrudRepository by inheritance.
public interface YourClassRepository extends JpaRepository<YourClass, Long> {
// you already have all the CRUD methods
// you can also create own queries just introducing their signatures like below:
List<YourClass> findByName(String name);
}
And you are ready to perform all CRUD operations as save, findAll, findOne, delete (and some other methods).
If in a typical Java application you have to write a class that implements YourClassRepository here comes the main power of Spring Data JPA – you don’t have to write any implementation of the repository interface. Spring Data JPA creates an implementation on the fly when you run your application.
Spring Data JPA also allows you to define other query methods by simply declaring their method signature. In this example it is shown with a findByName() method. That's because you have the name field in YourClass, you can create such queries with any other fields.
Then you can simply inject your repository and use it in your controller or service class:
#Controller
public class YourClassController {
#Autowired
private YourClassRepository repository;
#RequestMapping(value = "entities", method = RequestMethod.GET)
public List<YourClass> list() {
return repository.findAll();
}
#RequestMapping(value = "entities", method = RequestMethod.POST)
public YourClass create(#RequestBody YourClass yourClass) {
return repository.saveAndFlush(yourClass);
}
#RequestMapping(value = "entities/{id}", method = RequestMethod.GET)
public YourClass get(#PathVariable Long id) {
return repository.findOne(id);
}
#RequestMapping(value = "entities/{id}", method = RequestMethod.PUT)
public YourClass update(#PathVariable Long id, #RequestBody YourClass yourClass) {
YourClass existingYourClass = repository.findOne(id);
BeanUtils.copyProperties(yourClass, existingYourClass);
return repository.saveAndFlush(existingYourClass);
}
#RequestMapping(value = "entities/{id}", method = RequestMethod.DELETE)
public YourClass delete(#PathVariable Long id) {
YourClass existingYourClass = repository.findOne(id);
repository.delete(existingYourClass);
return existingYourClass;
}
}
The excellent tutorial you should complete to understand it is Accessing Data with JPA.
What about configuring MySQL database, first you need to add mysql-connector-java dependency to Maven's pom.xml, and then provide the datasource details.
You can do it in the following ways: in your configurational Spring bean XML file or by using Java Annotations. But the easiest way to do it is by using Spring Boot and provide your datasource details in application.properties file as in example:
application.db.driver = com.mysql.jdbc.Driver
application.db.url = jdbc:mysql://localhost:3306/yourDbName
application.db.username = username
application.db.password = password
Finally in Spring Guides you can find a lot of very useful tutorials about using Spring project releases and techniques as recommended by the Spring team, starting from scratch and completing them step-by-step. They are usually short (15-20 minutes per guide) and very clear.
And of course you have to learn some build automation tool like Maven, Gradle, Ant – it is incredibly handy. Here is the article about how to start using Maven for very beginners: Maven in 5 Minutes.
Good luck with your studying.
Related
As I am gradually trying to remove Dependencies on Spring in the domain part of my library without minimal extra effort, I now turn to Spring Data and the Repositories
Originally we annotated our domain entities to look like this:
#Document
public void MyEntity {
#Id
#Getter private final EntityIdentifier identifier;
#PersistenceConstructor
public MyEntity( ... ) {}
...
}
and so on.
where #Document, #PersistenceConstructor and #Id originate from the Spring Project and some are for a specific database backend (MongoDB).
I would like to cut this dependency and use my own annotations, that make sense in my domain - #Document is definitly nothing my domain experts would understand when appearing on e.g an clas Chair or a Desk.
For de/serialization with Jackson, I can create mixins to add specific annotations to classes without modifying them in their origin.
Maybe there is a similar technique for Spring or some other way to achive this that is more elegant than creating a wrapping class?
Apparently I need some clarification:
Lets suppose we try to write a clean architecture application which consists out of the following modules: domain, adapters, application. In the domain module, I have my domain logic and domain entities and everything domainy. I do not have anything springy - no dependency on spring whatsoever, not even by having a dependency that somehow depends on spring.
In the adapters and application module, I do have dependencies on spring. I might use spring-data to implement the Repository-Adapters. I will use Spring to configure and glue together the application.
Now, in my domain module I have the following classes:
#AllArgsConstructor
#HashAndEquals(of="identifier")
#DomainEntity // <-- This is an Annotation that has no dependency on Spring!
public class DomainEntity {
#DomainId // <-- This is an Annotation that has no dependency on Spring!
#Getter private final DomainEntityIdentifier identifier;
#Getter #Setter private String someValue;
...
}
#HashAndEquals
#AllArgsConstructor
public class DomainEntityIdentifiers {
#Getter private final String name;
}
public void interface DomainEntityRepository {
DomainEntity findById(DomainEntityIdentifier identifier);
void save(DomainEntity domainEntity)
void deleteById(DomainEntityIdentifier identifier);
}
Now the task is, to provide the implementation of that interface in the adapters module, using Spring Data - e.g. spring-data-mongo and inject this adapter to the domain in the application module.
Now, surly I can create an class, lets say DomainEntityMongo which is basically the same as the DomainEntity just with the spring-data-mongo-annotations, then a public interface MyEntityRepository extends CrudRepository<EntityIdentifier, MyEntityMongo> and implement the interface DomainRepository by using MyEntityRepository and converting there and back again between DomainEntityMongo <=> DomainEntity.
What I am looking for is a more magical/generical solution. E.g.
Having jackson-style mixin-classes, which provide Spring with the necessary/missing meta-data to do the work
Configuring Spring to use non-spring-annotations to do the work (just as it is possible with the ComponentScan for non-component-inheriting Annotations)
Or - if the data guys have crafted another innovative solution - this innovative solution.
you can use
#JsonDeserialize(using = yourCustomizedDeserializer.class)
have a look here
https://www.baeldung.com/jackson-deserialization
you can customize your persistence strategy with #Persister. You may, for example, specify your own subclass of org.hibernate.persister.EntityPersister or you might even provide a completely new implementation of the interface org.hibernate.persister.ClassPersister that implements persistence via, for example, stored procedure calls, serialization to flat files or LDAP.
is that what you are looking for?
So I have an AppUser class:
#Data
#Builder
#Document(collection = "app_users")
#Component
#AllArgsConstructor
#NoArgsConstructor
#Import(AppConfig.class)
public class AppUser {
#Id
#NotBlank(message = ErrorConstants.ANDROID_USER_ACCOUNT_MANAGER_ID_IS_NULL)
private String androidUserAccountManagerId;
#NotBlank(message = ErrorConstants.NULL_NAME)
private String name;
private Friend bestFriend;
#Setter(AccessLevel.NONE)
private FriendList friendList;
private boolean manualBestFriendOverride;
public Optional<Friend> getFriend(String friendName) {
return friendList.getFriend(friendName);
}
public void calculateBestFriend() {
if (!manualBestFriendOverride) {
bestFriend = friendList.calculateAndReturnBestFriend();
}
}
}
I have created an AppUserRepository interface that extends MongoRepository:
#Repository
public interface AppUserRepository extends MongoRepository<AppUser, String> {}
I have a WebController class that interacts with the interface. The AppUserRepository field in this class is #Autowired. This all seems to work but I have a few questions regarding how, and how I go forward and write integration tests for this:
How do I configure this AppUserRepository that has been created? Can I run it on a specific port etc?
Why has the Autowiring worked as I have not created this AppUserRepository Bean in an AppConfig like I have other Beans that are Autowired in my application.
If I was to create a Bean, wouldn't I also have to implement the class and return the instantiation? I started doing this but I had to implement all of the MongoRepository classes methods which I wasn't sure seemed quite right.
How do I write integration tests with an AppUserRepository? I need an AppUserRepository for my requests to interact with, but I do not want this to be the same DB as the real-time application DB when the service is up and running. Can I #Autowire the database into the integration test class and then close the DB after the integration tests run? If this is how I go forward, I think I then need to do point 3 above.
Thanks for your help in advance, I have tried reading some documentation but I think I am missing some key knowledge that means it is all quite overwhelming and confusing.
Thanks!
That's actually quite a big story to tell. This topic is called Spring Data JPA, Hibernate. You might wanna do a research on that, and watch some tutorials and so on.
Briefly, that MongoRepository just gives you a lot of methods which you can use. You can also define your own methods, add queries and etc.
Your starting points: https://www.baeldung.com/spring-boot-hibernate
https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa
https://www.baeldung.com/spring-data-jpa-query
Of course you can set a port number (and some other properties) via application.properties file. This is a list of most common properties, you can find properties for mongodb on it:
https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html
Now about bean. You basically created one with #Repository annotation actually. So Spring Context loads it on the start of application. You can autowire it.
I have created a simple controller
#GetMapping("/playerAccount")
public Iterable<PlayerAccount> getPlayerAccounts(com.querydsl.core.types.Predicate predicate) {
return repository.findAll(predicate);
}
When I call the GET /playerAccount API, I get the exception IllegalStateException "No primary or default constructor found for interface com.querydsl.core.types.Predicate" (thrown by org.springframework.web.method.annotation.ModelAttributeMethodProcessor#createAttribute).
After some (deep!) digging, I found out that if I delete the following line in my spring.xml file:
<mvc:annotation-driven />
And if I add the following line in my Spring.java file:
#EnableWebMvc
then the problem disappears.
I really don't understand why. What could be the cause of that ? I thought that these were really equivalent (one being a xml based configuration, the other being java/annotation based).
I read this documentation on combining Java and Xml configuration, but I didn't see anything relevant there.
edit:
from the (few) comments/answers that I got so far, I understand that maybe using a Predicate in my API is not the best choice.
Although I would really like to understand the nature of the bug, I first want to address the initial issue I'm trying to solve:
Let's say I have a MyEntity entity that is composed of 10 different fields (with different names and types). I would like to search on it easily. If I create the following (empty) interface:
public interface MyEntityRepository extends JpaRepository<MyEntity, Long>, QuerydslPredicateExecutor<MyEntity> {
}
then without any other code (apart from the xml configuration ), I am able to easily search a myEntity entity in the database.
Now I just want to expose that functionality to a Rest endpoint. And ideally, if I add a new field to my MyEntity, I want that API to automatically work with that new field, just like the MyEntityRepository does, without modifying the controller.
I thought this was the purpose of Spring Data and a good approach, but please tell me if there's a better / more common way of creating a search API to a given Entity.
I didn't see that it returned an exception, that's why I thought it was a dependency problem.
Try to make your code look like this, and it will do it.
#RestController
public class MyClass {
#Autowired
private final MyRepository repository;
#GetMapping("/playerAccount")
public Iterable<PlayerAccount> getPlayerAccounts() {
return repository.findAll();
}
If you have a parameter in your request you add #RequestParam.
Code time (yaaaaaay) :
#RestController
public class MyClass {
#Autowired
private final MyRepository repository;
#GetMapping("/playerAccount")
public Iterable<PlayerAccount> getPlayerAccounts(#RequestParam(required = false) Long id) {
return repository.findById(id);
}
Ps: the request should keep the same variable name e.g
.../playerAccount?id=6
My project manager wants me to use DAO/DTO objects to access and retrieve data from database. Project is written in Java SE without using any framework or ORM. His arguments is to make code more testable and to improve code design. Does it make sense?
How about initializing DAO object? Should it be initialized when the instance of class having DAO field is created:
private PersonDao personDao = new PersonDaoImpl();
or rather initialized when it is necessary?
public class A {
private PersonDao person;
public List<Person> findAll() {
person = new PersonDaoImpl();
return person.getAll();
}
}
It allows to mock this interface easily, but is it right to the DAO pattern usage convention?
The Data Access Object is basically an object or an interface that provides access to an underlying database or any other persistence storage.
That definition from: http://en.wikipedia.org/wiki/Data_access_object
Maybe a simple example can help you understand the concept:
Let's say we have an entity to represent an employee:
public class Employee {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The employee entities will be persisted into a corresponding Employee table in a database. A simple DAO interface to handle the database operation required to manipulate an employee entity will be like:
interface EmployeeDAO {
List<Employee> findAll();
List<Employee> findById();
List<Employee> findByName();
boolean insertEmployee(Employee employee);
boolean updateEmployee(Employee employee);
boolean deleteEmployee(Employee employee);
}
Next we have to provide a concrete implementation for that interface to deal with SQL server, and another to deal with flat files, etc...
Hope that helps
To maximimze the benefits of testability and separation of concerns you should introduce the concept of Inversion of Control (IoC). When applying IoC to the management of object lifecycles the term Dependency Injection is used. What this means is that your class A should be completely agnostic of which implementation is instantiated when.
In order to achieve this you need an extra component to bootstrap your application and inject all classes with the correct implementations.
You could set up your dependency-receiving class like this (setter injection, you can also use constructors)
public class PersonServiceImpl implements PersonService {
private PersonDao personDao;
public List<Person> findAll() {
return personDao.getAll();
}
public setPersonDaoA(PersonDao personDao) {
this.personDao = personDao;
}
}
And a component to do the dependency injection:
public class ApplicationContext {
private PersonService personService;
private PersonDao personDao ;
public PersonService getPersonService() {
if (personService == null) {
personService= new PersonServiceImpl();
personService.setPersonDao(getPersonDao());
}
return personService;
}
public PersonDao getPersonDao() {
if (personDao == null) {
personDao = new PersonDaoIml();
}
return personDao ;
}
}
Then application startup would involve this:
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ApplicationContext();
PersonService personService = ctx.getPersonService();
personService.findAll();
}
}
As you can see, the ApplicationContext encapsulates knowlegde about:
which implementations to use
in which order to set a chain of dependencies
which dependencies are already instantiated or not
The PersonServiceImpl class is now completely testable and all concerns regarding object lifecycle management have been extracted from it.
In real life this if often done using a framework like Spring or CDI (which is becoming more and more popular recently). But in your situation, starting off with an approach like above might be a good first step. It will reap the immediate benefits mentioned by your project manager without incurring the overhead of introducing Spring, possibly changing your build too and having to learn how that works (e.g. with an XML context, source code context and/or annotations).
Introducing Spring at a later stage will be easy because all classes are already prepared for Dependency Injection. Just keep in mind that your factory (ApplicationContext in my example) should not take on any extra responsibilities like configuration management.
Also keep in mind that the above example of ApplicationContext is not a singleton. You yourself should make sure only one instance of it is created when your application starts, and all injections are handled by it. Creating duplicate instances could cause confusing bugs.
The DAO pattern is not an "enterprise" pattern. It's mostly seen in "enterprise" applications, but you can absolutely use in a an application written in SE only.
It's not because you're writing an SE application that you don't have to test, so indeed, your code will be more testable using the DAO pattern and IOC rather than using straight JDBC in your application.
The way you're implementing your class using the DAO is problematic because your class cannot be tested properly because of the tight coupling between your class A and your DAO implementation. You're better off using the IOC pattern as well with a framework like Guice or Dagger (both designed with SE in mind).
For a code example, look at slnowak's answer.
The way you are using it, it is still tightly coupled with your class A.
You should provide your DAO as a dependency, using constructor or setter. Probably the most preferable way is to use some kind of Inversion of Control (for example dependency injection framework).
Your class A should be something like:
public class A {
private PersonDao personDao;
// possibly an #Inject annotation
public A(PersonDao personDao) {
this.personDao = personDao;
}
public List<Person> findAll() {
return personDao.getAll();
}
}
And actually, I would consider it an antipattern this way. It depends on how you are about to use your class A.
If it contains different business logic - fine.
If it just dispatches a call to DAO (I don't like this name, maybe use Repository instead ;)) then it is just unnecessary layer of abstraction.
Another thing - you mentioned DTO. So a Person class is just a DTO in this case? Here we could have another antipattern. DTO is fine for example if you need to transform your business object(s) into something that is visible on the screen. Or to separate perstistence model from business model.
What I'm trying to say is: don't make a Person class just a data structure. Give it some behaviour.
I am working on three different tables. I am using Hibernate to query these tables. I implemented successfully the DAO and the service layers, but i have few problems with the controller package. Here is my code, my controller package contains 3 classes , each should handle a table (i have 3 tables as i said before).
#Controller
public class Ods_Gis_Actel_Controller {
Param_Gis_Actel_Controller Param = new Param_Gis_Actel_Controller();
Tbl_Dim_Actel_Controller Dim = new Tbl_Dim_Actel_Controller();
#Autowired
Ods_Gis_Actel_metier service;
#RequestMapping(value="/index")
public String pageIndex(Model model)
{
addOdsTable(model);
Param.addParamTable(model);
Dim.addDimTable(model);
return "Affichage";
}
public void addOdsTable(Model model)
{
model.addAttribute("listeOds",service.getAll());
}
}
#Controller
public class Param_Gis_Actel_Controller {
#Autowired
Param_Gis_Actel_metier service;
public void addParamTable(Model model)
{
model.addAttribute("listeParam",service.getAll());
}
}
#Controller
public class Tbl_Dim_Actel_Controller {
#Autowired
Tbl_Dim_Actel_metier service;
public void addDimTable(Model model)
{
model.addAttribute("listeDim",service.getAll());
}
}
The request mapping is done in the 1st class, whose method calls 2 other methods from the other classes. But it seems, that the autowiring works only in the class, where the RequestMapping is performed.
Is this true?
how can i use the other methods from the classes which don't contain the RequestMapping if the autowiring doesn't work for them?
I gone through your problem , I think you are not so much aware the objective of #Controller , #RequestMapping . So First of all you need to know , why we use #Controller?, this is used to give business logic to your request. When request is hited from user , then your DispatcherServlet match the url from your request to value of RequestMapping annotation of all defined controller. And according to that , the matched mapping method is called and further procees done by framework. Now come to #Autowire, this is used to load the bean class definition from the xml configuration. So the #Autowire and #RequestMapping having different objective . So it's wrong to say here that the
**autowiring** works only in the class where the RequestMapping is performed.
Now your second question , How you can use simple class? there are two ways to achieve that as far as I know,
1) To create the Object of that class inside your class as you done in your code
2) To create the instance of that class using factory-method.
for the second point , you have to first define your class inside the configuration file by following the below format
<bean id="paramGis" class="<whatever_package_detail>.Param_Gis_Actel_Controller" factory-method="createInstance"/>
here one things you have to care that this method should be static .
and your class would look like that
#Service
public class Param_Gis_Actel_Controller {
private static Param_Gis_Actel_Controller paramGis;
public static Param_Gis_Actel_Controller createInstance(){
if(paramGis==null){
return new Param_Gis_Actel_Controller();
}
return paramGis;
}
public void addParamTable(Model model)
{
model.addAttribute("listeParam",service.getAll());
}
}
If you are still getting problem let me know.
I think you are having difficulties with the Java/Spring way. We don't use #Controller/#Autowired like that.
It's kind of hard to explain shortly (I strongly recommend you read the official document for that), but in short, you shouldn't create a Controller object inside another controller. The objects with annotation marks (#Controller, #Service...) should be generated and managed by Spring. At initiation time they will be injected with the #Autowired services by "Spring" way. Of courses you can intervene into that process, but by other special methods.
P/s: your naming convention is not for Java ;). If you create a program for personal use it maybe ok, but you will have difficult times collaborating with other Java developers.
Through method name as default one for access that particular method or use #Qualifier annotations.