I'm pretty new to the concept of patterns. I am practising my dependency injection skills as well as using DAO principles. The code I have written works but I feel that it can be written in a more elegant fashion. I've tried restructuring it a pattern I saw but that complicated things so not sure if I implemented it correctly. As a general rule when a web application communicates with a database and throws out result, how should one structure their project?
I've heard of the MVC principle but that doesn't necessarily add database to the mix.
This is what I have so far:
A class containing a controller in a Controller package:
#RestController
public class ResponseController {
#Autowired
MongoBase dbConnection;
#RequestMapping(value = "/jsonresult", method = RequestMethod.GET)
#ResponseBody
public String jsonresult(#RequestParam(value = "id", required = true) String id){
return dbConnection.documentToJSON(id, Constants.database,Constants.collection);
}
#RequestMapping(value = "/alljsonresult", method = RequestMethod.GET)
#ResponseBody
public String alljsonresult(){
return dbConnection.allDocumentToJSON(Constants.database,Constants.collection);
}}
A class containing CRUD methods to the database in a Database package:
#Component
public class MongoBase {
#Autowired
MongoClient mongoClient;
public MongoBase() {
try {
mongoClient = new MongoClient("localhost", 27017);
} catch (Exception e) {
e.printStackTrace();
}
}
public void printAllCollection(String databaseName, String collectionName) {
...
}
So is there a better way/more efficient way of writing thi? Also I feel I haven't fully implemented DI in the Monogbase class since it contains the new keyword..
If you are using springboot, then you don't need this old style
also don't need to create mongoClient bean your self, spring boot help you in it
You just need to add following properties in application.properties file
#mongodb
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=app1
Also declares a spring-boot-starter-data-mongodb in your pom or gradle
it's a cool and super awesome dependency for accessing Data with MongoDB
you can read about it from here[https://spring.io/guides/gs/accessing-data-mongodb/]
suppose you have a domain
#Document(collection = "domain")
public class User {
#Id
private long id;
#Indexed(unique = true)
private String domain;
private boolean displayAds;
//getters and setters
}
Now if we need to perform curd operation on this domain, extends MongoRepository, you have CRUD function automatically. Spring data come with many magic findBy queries, review the official Spring data MongoDB – Query methods for detail.
public interface UserRepository extends MongoRepository<User, Long> {
Domain findFirstByDomain(String domain);
Domain findByDomainAndDisplayAds(String domain, boolean displayAds);
//Supports native JSON query string
#Query("{domain:'?0'}")
Domain findCustomByDomain(String domain);
#Query("{domain: { $regex: ?0 } })")
List<Domain> findCustomByRegExDomain(String domain);
}
UserRepository extends the MongoRepository interface and plugs in the type of values and id it works with: User and Long. Out-of-the-box, this interface comes with many operations, including standard CRUD operations (create-read-update-delete).
now you can easly use it in your controller
#RestController
public class ResponseController {
#Autowired
UserRepository userRepository;
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
User create(#RequestBody #Valid User user) {
return userRepository.create(user);
}
}
also you can do with it lot of things. you just need to go throw with it doc.
Also you you can use mongoTemplate for execute the query
#Autowired
MongoTemplate mongoTemplate;
When I build web applications I typically define the full chain as follows:
Client Side:
View - This is the V in MVC where you control visuals & user action derived workflow.
Controller - This is the C in MVC where workflow is managed. Most Client processing will go here and multiple Client calls can be made to get/send data or perform lookups.
Client - This is where you make a call to a REST web service and parse/deserialize the results/handle exceptions.
Server Side:
RestController (Sometimes Called Resource) - This is your REST API endpoint. Here you extract & validate a request.
Service - This is where most of your server logic will go. Sometimes you might have to make multiple data access calls or call other service functions.
DataAccessObject (Sometimes Called Provider) - This is your database interaction to pull data from your database into a model. CRUD operations (Create Read Update Delete)
Example Scenario:
Lets say we want to submit data & permissions for a given user
UserView.jsp - User types in user & permission data and hits submit.
UserController.java - validates User & permission data, does any necessary lookups, then calls UserClient.
UserClient.java - Builds the REST request and calls the /user/create REST endpoint.
UserRestController.java - Unpackages/Validates the request, then calls UserManagementService
UserManagementService.java - Server Logic happens here! Lets say I have two tables in my database. A User table and a Permissions table. I want to store the user information in the User table and the permission information in the permission table so I will call the UserDAO for the user data and the PermissionDAO for the permission data.
UserDAO & PermissionDAO - Saves The passed models to their respective tables.
Return to Service, Return to RestController, Return to Client (Parse Response), Return to Controller (Move the Workflow forward with a redirect or a success message).
Conclusion:
This may seem like a lot of in-between steps but this design provides a ton of flexibility, especially if your building large, complex web services. Each component has a specific purpose, follows an easy naming convention, and splits complex logic into smaller, simpler steps.
I'd like to recommend some improvements to your solution:
You're using Spring. You should not create any injected beans using new. Let Spring instantiate and manage those beans for you.
Use the #Repository annotation to mark your persistence class.
Make your repository class interface based.
Don't embed "Mongo" into the class name. You happen to be using Mongo as your persistence provider now, but you may change your mind later. Don't reveal implementation information in your class names - hide it.
The Controller is part of the UI. It uses repositories and/or services to fulfill use cases. It's perfectly correct to use Spring to inject the repository into the Controller.
I'd recommend that you use Spring Boot, an opinionated version of Spring. Have a look at their guides to learn how to use it properly.
Related
I have a question regarding the transactional boundaries in REST-Controllers using Java/Jakarta EE and JAX-RS.
Given the following controller, when a user is created in the #POST method, first the user is created using a dedicated service. Afterwards, the user´s permissions are stored using a different service.
Both services wrap incoming calls in a container managed transaction.
#Path("/users")
public class UserController {
#Inject
private UserService userService;
#Inject
private PermissionService permissionService;
#POST
public UserDto createUser(UserDto userDto) {
User user = mapToUser(userDto);
User createdUser = userService.create(user);
Permissions perms = mapToPermissions(userDto);
permissionService.createPermissions(createdUser.getId());
return mapToUserDto(createdUser);
}
}
From my point of view, there exists a transactional boundary around userService.create() and a second one around permissionService.createPermissions(). Can you confirm that this is true?
Secondly, if the previous statement is true, and the applications shuts down mid processing, the users permissions might not be persisted. Is this appraoch considered bad practise and should both operations be performed in a single transaction (or in the REST-paradigm under different ressources / endpoints)?
You are correct, there are two transactions, so the first could succeed while the second fails.
A common practice is using a Service Façade pattern. A coarse grained service that sets the transactions boundaries, and call the services to achieve the result.
I am new to graphql. I want to implement backend in spring boot using graphql. I am still confused about endpints. So if i have 2 entities user and product. so do i have to implement 2 endpoints
#RequestMapping(value="/graphql/user", method=RequestMethod.POST, produces = "application/json")
public GraphQLResponse<Object> getService(#RequestHeader HttpHeaders headers, #RequestBody GraphQLRequest graphql) {
GraphQLResponse<Object> execute = graphQLService.execute(headers, graphql);
return execute;
}
like this one for user and another one for product. or just one.
No you need only one Endpoint. I suggest you to use this library. With this library it is very easy to start into the world of GraphQL:
https://github.com/leangen/GraphQL-SPQR
And a good example with this library and Springboot you find here, just clone the repo and run it local:
https://github.com/leangen/graphql-spqr-samples
Install this Plugin in Chrome to get read and query your schema easely:
https://chrome.google.com/webstore/detail/chromeiql/fkkiamalmpiidkljmicmjfbieiclmeij
I hoped this answer helped you.
With spring-boot-grpahql, there's no need to write controller at all. You just need to write ORM layer rest will be taken care by it. Here's an example implementation of GraphQL in java using spring-boot, gradle, spring-jpa and mongo.
Graphql exposes only one endpoint and depending on your setup it may be accessible like this: http://localhost:8080/graphql. Usually you never access graphql directly but rather via libraries that perform actions that allow you to communicate with graphql (like type-checking, converting between graphql types and your types and more).
Java GraphQL Kickstart is one of them and all you do is define schema and write resolvers for your queries, mutations and subscriptions:
schema {
query: Query
}
type Query {
allUsers: User
}
type User {
id: ID!
firstName: String
lastName: String!
}
And your resolver:
package your.project.resolvers;
import graphql.kickstart.tools.GraphQLQueryResolver;
import org.springframework.stereotype.Service;
import your.project.domain.persistence.User;
import your.project.repository.UserRepository;
import java.util.List;
#Service
public class UserResolver implements GraphQLQueryResolver {
private final UserRepository userRepository;
// be carefull about the name of this method
public List<User> allUsers() {
// perform actions based on your needs
return userRepository.findAll();
}
}
Notice that I'm using service annotation because this is basically performing some business logic on data retrieved from persistence layer. Also the name of the method allUsers() in the UserResolver is important. GraphQL will look for it based on your schema like this:
trying exact match with allUsers
prepending get: getAllUsers
I'm trying to refactor the existing code base of one of my project following Repository pattern, so that i can make the project more re-usable and testable.
I've written services, repositories, when I try to set Authentication, Authorization and Transactional annotation on service layer, I am facing issues.
These annotations works only on controller level, but not on service layer, so I want a way for annotate service methods.
Is it possible to do so?
It would be helpful, if someone points me samples using repository pattern on Play framework or better way to proceed further.
Authentication and authorization only make sense on a request, so sticking them on anything but a controller method is not going to work either way.
Transactional is just a helper annotation to wrap the entire request in a JPA transaction. It is usually advisable to do the wrapping yourself anyway, so you don't really need that. Example taken from the documentation:
#Inject
private JPAApi jpaApi;
public void updateSomething() {
// do something with the entity manager, per instance
// save, update or query model objects.
jpaApi.withTransaction(() -> {
EntityManager em = jpaApi.em();
Query query = em.createNativeQuery("update people set active = 1 where age > 18");
query.executeUpdate();
});
}
I currently have been reading and trying out MongoDB with Spring REST framework.
I have the following code for the controller:
#RestController
#RequestMapping("/users")
public class UserController {
#Autowired
private UserRepository userRepo;
#RequestMapping(value = "/info2", method = RequestMethod.GET)
public List<User> getAllUser(){
List<User> users = userRepo.findByEmail("test#test.com");
return users;
}
#RequestMapping(value = "/save", method=RequestMethod.POST)
public User createUser(#RequestBody User user){
return userRepo.save(user);
}
}
However, when I call
localhost:8080/users, it returns back
{
_links: {
self: {
href: "http://localhost:8080/users{?page,size,sort}"
templated: true
}-
search: {
href: "http://localhost:8080/users/search"
}-
}-
page: {
size: 20
totalElements: 0
totalPages: 0
number: 0
}-
}
I want the URI /users/info2 to return back the list of users by that particular email. How do I do that?
Also, here are the outstanding questions I have:
Can I just use MongoDBTemplate instead of the MongoRepository? I want more customized queries, and I couldn't find any in depth examples on the web.
How does Spring framework map the xml config file, for example, in cases like when I setup multiple MongoDB connections?
So without your configs, but looking at your existing code and service response, one can make some general assumptions. Your Repository is annotated with #RepositoryRestController which not only provides Spring Data access but also exposes a common ReST endpoint for your repository.
This can be determined from two aspects of your post. First you don't appear to be using HATEOAS in your Controller class, yet your service exposes JSON + HAL. Furthermore your response exposes the paging and sorting feature of Mongo Repository as well as the search behavior of Spring Data Repositories when annotated with #RepositoryRestController.
If you don't want this behavior, change the annotation on your Repository to #Repository instead.
Also to answer your other questions:
1. you can annotate methods if you want with queries on Spring Data Repositories, you can also use any class in the stack managed by spring you want, but why?
I suggest reading about the bean lifecycle to understand the dependency management within spring, there are plenty of presentations (including one in my github repo). If you have multiple connections, you can define your repository beans to utilize anything you wire it. There is a lot more manual operations at that point, and it will take some understanding and through to make it work. There is no way to give you a simple "do xyz" type answer without a lot more information.
I am new using Spring's MVC (but Ive been using it for some years at other php frameworks).
I have many doubts, I read the spring info and seems to be right and all.. then Ichecked this tutorial http://javahash.com/spring-4-mvc-hello-world-tutorial-full-example/ and it works and all, but on the controller part, there is a code I dont understand, and Id like to know how to properly use the Models on Spring.
As far as I know, the models should call make the calls to the db, so, what about the services (interfaces and implementations) and the DTOs?
At the example they make something like this:
#Controller
public class HelloWorldController {
#RequestMapping("/hello")
public String hello(#RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "helloworld";
}
}
It receives a model as parameter... I bet if there is any, Spring would use a default one, what if I want to add more interaction and lets say, specifiy a model to call the db? Any idea how I could do that?
And if I want to add a service... I am a little bit clueless about it, if someone could help me to understand...
Thanks in advance
Model is a map representing the data that the view needs. It can contain one or more entities, or simple objects, or strings, or whatever you want.
MVC doesn't require the use of a database. The model does not "call the db". You can inject a repository into your controller to load data from a db into your model.
#Controller
#RequestMapping("/foo")
public class FooController {
#Autowired
private FooRepository fooRepository;
#RequestMapping
String getFoos(Model model) {
List<Foo> foos = fooRepository.findAll();
model.addAttribute("foos", foos);
model.addAttribute("someOtherDataYourViewNeeds", "bar");
return "foo/list";
}
}
This Model Object is injected by spring, and his content will be sent to the view.
You can see the documentation for Model interface here http://docs.spring.io/spring-framework/docs/current/javadoc-api/.
If you wanna access some object on your view, you can you use
model.addAttribute(object).
I think you could read The IoC Container documentation to understand how spring works.