where microservices code in https://dzone.com/articles/spring-boot-creating project ? - spring-boot

These days I'm hearing a lot about microservices and wondering to create POC (Proof of Concept) in order to be get applied in my project which will begin from scratched. I read a lots of blog about the mocroservices and found this link : https://dzone.com/articles/spring-boot-creating. I was able to successfully run the code mentioned in the link. But I feels that its a Simple Spring Boot REST example, I am not sure what is the role of microservices in this example ? I'd like to understand this from technical point of view now as I theoretically understand what it is. Please guide.
Please see code below for reference:
curl -vvv "http://localhost:8080/order?idCustomer=2&idProduct=3&amount=4"
Trying 127.0.0.1...
Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /order?idCustomer=2&idProduct=3&amount=4 HTTP/1.1
> Host: localhost:8080 > User-Agent: curl/7.46.0
> Accept: / > < HTTP/1.1 200 < Content-Type: application/json < Content-Length: 173
< Date: Fri, 09 Sep 2016 07:22:02 GMT
< {"id":1,"amount":4,"orderDate":1473405722862,"customer":{"id":2,"name":"Customer 2","email":"Customer2#gmail.com"},"product":{"id":3,"sku":"abcd3","description":"Product3"}}* Connection #0 to host localhost left intact
Application.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
ApplicationConfig.java
#Configuration
public class ApplicationConfig {
#Named
static class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
this.packages("br.com.alexandreesl.handson.rest");
}
}
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
return restTemplate;
}
}
Customer.java
public class Customer {
private long id;
private String name;
private String email;
// setters and getters
}
CustomerRest.java
#Named
#Path("/customer")
public class CustomerRest {
private static List<Customer> customers = new ArrayList<Customer>();
static {
Customer customer1 = new Customer();
customer1.setId(1);
customer1.setName("Customer 1");
customer1.setEmail("customer1#gmail.com");
Customer customer2 = new Customer();
customer2.setId(2);
customer2.setName("Customer 2");
customer2.setEmail("Customer2#gmail.com");
Customer customer3 = new Customer();
customer3.setId(3);
customer3.setName("Customer 3");
customer3.setEmail("Customer3#gmail.com");
Customer customer4 = new Customer();
customer4.setId(4);
customer4.setName("Customer 4");
customer4.setEmail("Customer4#gmail.com");
Customer customer5 = new Customer();
customer5.setId(5);
customer5.setName("Customer 5");
customer5.setEmail("Customer5#gmail.com");
customers.add(customer1);
customers.add(customer2);
customers.add(customer3);
customers.add(customer4);
customers.add(customer5);
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Customer> getCustomers() {
return customers;
}
#GET
#Path("/getCustomer")
#Produces(MediaType.APPLICATION_JSON)
public Customer getCustomer(#QueryParam("id") long id) {
Customer cli = null;
for (Customer c : customers) {
if (c.getId() == id)
cli = c;
}
return cli;
}
}
Order.java
public class Order {
private long id;
private long amount;
private Date orderDate;
private Customer customer;
private Product product;
// setters and getters
}
OrderRest.java
#Named
#Path("/")
public class OrderRest {
private long id = 1;
#Inject
private RestTemplate restTemplate;
#GET
#Path("order")
#Produces(MediaType.APPLICATION_JSON)
public Order submitOrder(#QueryParam("idCustomer") long idCustomer,
#QueryParam("idProduct") long idProduct,
#QueryParam("amount") long amount) {
Customer customer = restTemplate.getForObject("http://localhost:8080/customer/getCustomer?id={id}", Customer.class, idCustomer);
Product product = restTemplate.getForObject("http://localhost:8080/product/getProduct?id={id}", Product.class,idProduct);
Order order = new Order();
order.setCustomer(customer);
order.setProduct(product);
order.setId(id);
order.setAmount(amount);
order.setOrderDate(new Date());
id++;
return order;
}
}
Product.java
public class Product {
private long id;
private String sku;
private String description;
// setters and getters
}
ProductRest.java
#Named
#Path("/product")
public class ProductRest {
private static List<Product> products = new ArrayList<Product>();
static {
Product product1 = new Product();
product1.setId(1);
product1.setSku("abcd1");
product1.setDescription("Product1");
Product product2 = new Product();
product2.setId(2);
product2.setSku("abcd2");
product2.setDescription("Product2");
Product product3 = new Product();
product3.setId(3);
product3.setSku("abcd3");
product3.setDescription("Product3");
Product product4 = new Product();
product4.setId(4);
product4.setSku("abcd4");
product4.setDescription("Product4");
products.add(product1);
products.add(product2);
products.add(product3);
products.add(product4);
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Product> getProducts() {
return products;
}
#GET
#Path("/getProduct")
#Produces(MediaType.APPLICATION_JSON)
public Product getProduct(#QueryParam("id") long id) {
Product prod = null;
for (Product p : products) {
if (p.getId() == id)
prod = p;
}
return prod;
}
}

Related

Spring RestController returns 400 Bad Requests for POST Request (used #RequestBody)

I have a simple code snippet below (I did not extends existing repository interface, just try to do things in memory). The GET request works but the POST request returned 400 Bad Request.
I send JSON data to the localhost:8080/v1/products in the below format
{
"productId": 4,
"name": "Amazon Alexa",
"price": 500.0,
"description": "AI device"
}
Controller class
#RestController
#RequestMapping("/v1")
public class ProductController {
private ProductRepository productRepo;
private ProductController(ProductRepository productRepo) {
this.productRepo = productRepo;
}
#GetMapping("/products")
public List<Product> getProduct() {
return productRepo.findAllProducts();
}
#PostMapping("/products")
public List<Product> postProduct(#RequestBody Product product) {
return productRepo.saveProduct(product);
}
}
Repository class
#Repository
public class ProductRepository {
Boolean isLoaded = false;
Product product1 = new Product(1, "Apple TV", 300.0, "This is a TV");
Product product2 = new Product(2, "Samsung Tablet", 900.0, "This is on sale");
Product product3 = new Product(3, "Google Home", 100.0, "Smart AI device");
List<Product> products = new ArrayList<Product>();
private void loadProducts() {
if (!isLoaded) {
products.add(product1);
products.add(product2);
products.add(product3);
isLoaded = true;
}
}
public List<Product> findAllProducts() {
loadProducts();
return products;
}
public List<Product> saveProduct(Product product) {
loadProducts();
products.add(product);
return products;
}
}
Product class with getters/setters omitted, all argument constructor omitted
public class Product {
private int productId;
private String name;
private double price;
private String description;
}
Does anyone know what I missed? Thanks

Spring Boot Rest

i am practicing with spring boot for work with restful applications
I have set a #RestController and #Entity like this
#RestController
#RequestMapping(value = "/api")
public class RestControllerCar {
#Autowired
private CarRepository carRepository;
#RequestMapping(value = "/cars")
public Iterable<Car> getCars() {
return carRepository.findAll();
}
}
and
#Entity
public class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String brand, model, color, registerNumber;
private Integer year, price;
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
#ManyToMany(mappedBy = "cars")
private Set<Owner> owners;
public Car() {
}
public Car(String brand, String model, String color, String registerNumber, Integer year, Integer price) {
super();
this.brand = brand;
this.model = model;
this.color = color;
this.registerNumber = registerNumber;
this.year = year;
this.price = price;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getRegisterNumber() {
return registerNumber;
}
public void setRegisterNumber(String registerNumber) {
this.registerNumber = registerNumber;
}
public Integer getYear() {
return year;
}
public void setYear(Integer year) {
this.year = year;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
public Set<Owner> getOwner() {
return owners;
}
public void setOwner(Set<Owner> owners) {
this.owners = owners;
}
when i use postman to http://localhost:8080/cardatabase/api/cars i get a list of Cars
but even if i go to http://localhost:8081/cardatabase/cars, with _embedded on the top
it`s normal?
Thanks!!!!
Is your repository annotated #RestRepository? The _embedded make me think to the kind of output given by a #RestRepository for an array.
#RestRepository auto create all endpoint. As #M.Deinum pointed out, with the data rest starter, if ou remove it , you only have your controller, and not the one generated by #RestRepository.
Two main choices here:
You dont annotate the Repository. Just an interface which implement JpaRepository<YourEntity, TypeOfYourID> and use your controllers
You use only the auto created controllers by #RestRepository.
Or, you can install swagger2 on your project, so, accessing the docs on your browser, you will see all available endpoints, and it may be more clear for you.
With swagger you will also see what is the return type of the endpoint, the parameters etc..
Swagger is really easy to install in a project and to use. (dependencies, one annotation and it's good.. for basic usage).

Can I return DTO and domain entities from services?

I have a spring-boot application and I use DTO like that:
Service
#Service
public class UnitOfMeasureServiceImpl implements IUnitOfMeasureService {
private final IUnitsOfMeasureRepository unitOfMeasureRepository;
#Autowired
public UnitOfMeasureServiceImpl(IUnitsOfMeasureRepository unitOfMeasureRepository) {
this.unitOfMeasureRepository = unitOfMeasureRepository;
}
#Override
public UnitOfMeasureDTO getUnitOfMeasureById(UUID id) {
Optional<UnitOfMeasure> optionalUnitOfMeasure = unitOfMeasureRepository.findById(id);
if (!optionalUnitOfMeasure.isPresent()){
// throw new ComponentNotFoundException(id);
return null;
}
return UnitOfMeasureDTO.factory(optionalUnitOfMeasure.get());
}
dto:
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
public class UnitOfMeasureDTO {
private String id;
private String name;
private String description;
private String sourceInfoCompanyName;
private String originalId;
public static UnitOfMeasureDTO factory(UnitOfMeasure unitOfMeasure) {
UnitOfMeasureDTO dto = new UnitOfMeasureDTO();
dto.id = unitOfMeasure.getId().toString();
dto.name = unitOfMeasure.getName();
dto.description = unitOfMeasure.getDescription();
dto.sourceInfoCompanyName = unitOfMeasure.getSourceInfo().getSourceCompany().getName();
dto.originalId = unitOfMeasure.getOriginalId();
return dto;
}
}
controller:
#RestController
#RequestMapping(UnitOfMeasureController.BASE_URL)
public class UnitOfMeasureController {
public static final String BASE_URL = "/api/sust/v1/unitOfMeasures";
private final IUnitOfMeasureService unitOfMeasureService;
public UnitOfMeasureController(IUnitOfMeasureService unitOfMeasureService) {
this.unitOfMeasureService = unitOfMeasureService;
}
#GetMapping(path = "/{id}")
#ResponseStatus(HttpStatus.OK)
public UnitOfMeasureDTO getUnitOfMeasureDTO(#PathVariable("id") UUID id) {
UnitOfMeasureDTO unitOfMeasureDTO = unitOfMeasureService.getUnitOfMeasureById(id);
return unitOfMeasureDTO;
}
So in my service I have getUnitOfMeasureById(UUID id) that return a UnitOfMeasureDTO.
Now I need to call, from another service, getUnitOfMeasureById(UUID id) that return the domain entity UnitOfMeasure. I think it's correct to call a service method from another service (not a controller method!) and the separation between business logic is at the service layer. So is it correct to have 2 methods: getUnitOfMeasureDTOById and getUnitOfMeasureById in the service? (getUnitOfMeasureDTOById call getUnitOfMeasureById to avoid code duplication)

Cannot remove attributes in ldap with spring ldap

we need to make a spring boot project that works with spring ldap.
every things is good.But when we remove a member from a group,the member deleted form group (i see it in debug mode in a Setmembers) but, in ldap(Oracle Internet Directory) that member exists!
Please help me!
//Group Entry
#Entry(objectClasses = {"top", "groupOfUniqueNames", "orclGroup"}, base = "cn=Groups")
public final class Group {
#Id
private Name dn;
#Attribute(name = "cn")
private String name;
private String description;
private String displayName;
#Attribute(name = "ou")
private String ou;
#Attribute(name = "uniqueMember")
private Set<Name> members;
public void addMember(Name newMember) {
members.add(newMember);
}
public void removeMember(Name member) {
members.remove(member);
}
//Custom LdapUtils
public class CustomLdapUtils {
private static final String GROUP_BASE_DN = "cn=Groups";
private static final String USER_BASE_DN = "cn=Users";
public Name buildGroupDn(String name) {
return LdapNameBuilder.newInstance(GROUP_BASE_DN)
.add("cn","Charts")
.add("cn",name)
.build();
}
private static final CsutomLdapUtils LDAP_UTILS = new CsutomLdapUtils ();
private CsutomLdapUtils () {
}
public Name buildPersonDn(String name) {
return LdapNameBuilder.newInstance(USER_BASE_DN)
.add("cn", name)
.build();
}
}
//Controller
#DeleteMapping(value = "/memberOfGroup", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> removeMemberFromGroup(#RequestBody Map<String,String> map) throws NamingException {
List<Group> groupToFind = ldapSearchGroupsService.getGroupByCn(map.get("groupName"));
List<User> userToFind = ldapSearchUserService.getAllUserByUserName(map.get("userName"));
if (groupToFind.isEmpty()) {
//TODO : Group no found!
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
for (Group group1 : groupToFind) {
group1.removeMember(userToFind.stream().findAny().get().getDn());
//ldapBindGroupService.deleteMemberFromGroup(group1);
DirContextOperations ctx = ldapTemplate.lookupContext(CustomLdapUtils.getInstance().buildGroupDn(map.get("groupName")));
ctx.removeAttributeValue("uniqueMember",map.get("userName"));
ctx.rebind(CustomLdapUtils.getInstance().buildGroupDn(map.get("groupName")),map.get("groupName"));
ldapTemplate.modifyAttributes(ctx);
}
return new ResponseEntity<>(HttpStatus.OK);
}
}
Is some problem in code? or need some methods?
Finally after several search and debug,i found the problem!
In each ldap env,after every changes,the directory must be commit and apply.
In above code,i implemented that,but not in true way!
Best way is here:
#DeleteMapping(value = "/membersOfGroup", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> removeMemberFromGroup(#RequestBody Map<String,String> map) {
List<Group> groupToFind = ldapSearchGroupsService.getGroupByCn(map.get("groupName"));
List<User> userToFind = ldapSearchUserService.getAllUserByUserName(map.get("userName"));
if (groupToFind.isEmpty()) {
//TODO : Group no found!
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
for (Group group1 : groupToFind) {
group1.removeMember(userToFind.stream().findAny().get().getDn());
DirContextOperations ctx = ldapTemplate.lookupContext(CustomLdapUtils.getInstance().buildGroupDn(map.get("groupName")));
ctx.removeAttributeValue("member",CustomLdapUtils.getInstance().buildPersonDn(map.get("userName")));
//True way
ldapTemplate.update(group1);
}
return new ResponseEntity<>(HttpStatus.OK);
}
}

Java Spring 4 (Annotated) Rest Controller not being hit by REST Client tool in Firefox

Hi,
I have a problem that is very confusing for me because the mapping should work and it looks like it does map when the Spring Boot is started in debug mode. I don't know where else I can check for an obvious solution to this problem.
Here is the application.properties:
server.port=8082
server.contextPath = /
Here is the SpringBootInitializer class that adds a further "/api" to the >Servlet registration:
public class App extends SpringBootServletInitializer {
#Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
#Bean
public ServletRegistrationBean dispatcherServletRegistration() {
final ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet(), "/api/*");
final Map<String, String> params = new HashMap<String, String>();
params.put("contextClass", "org.springframework.web.context.support.AnnotationConfigWebApplicationContext");
params.put("contextConfigLocation", "org.spring.sec2.spring");
params.put("dispatchOptionsRequest", "true");
registration.setInitParameters(params);
registration.setLoadOnStartup(1);
return registration;
}
//
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.initializers(new MyApplicationContextInitializer()).sources(App.class);
}
public static void main(final String... args) {
new SpringApplicationBuilder(App.class).initializers(new MyApplicationContextInitializer()).run(args);
}
}
Here is the Controler which adds a further "users" to the mapping. The method >which I have set a debug point is the findAll and requires no futher mapping to >get to it (i.e. the root of /users/:
#Controller
#RequestMapping(value = users)
public class UserController extends AbstractController<User> {
#Autowired
private IUserService userService;
public UserController() {
super(User.class);
}
// API
// find
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public void getItsWorking() {
System.out.println("It's Working!!!");
}
}
Here is the User entity:
#Entity
public class User implements IEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="user_id")
private Long user_id;
#Column(name = "username", unique = true, nullable = false)
private String name;
#Column(unique = true, nullable = false)
private String email;
#Column(nullable = false)
private String password;
#Column(nullable = false)
private Boolean locked;
public User() {
super();
}
public User(final String nameToSet, final String passwordToSet, /*final
Set<Role> rolesToSet,*/ final Boolean lockedToSet) {
super();
name = nameToSet;
password = passwordToSet;
locked = lockedToSet;
}
// API
public Long getId() {
return user_id;
}
public void setId(final Long idToSet) {
user_id = idToSet;
}
public String getName() {
return name;
}
public void setName(final String nameToSet) {
name = nameToSet;
}
public String getEmail() {
return email;
}
public void setEmail(final String emailToSet) {
email = emailToSet;
}
public String getPassword() {
return password;
}
public void setPassword(final String passwordToSet) {
password = passwordToSet;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(final Boolean lockedToSet) {
locked = lockedToSet;
}
}
Here is the output on my Spring Boot debug when it starts up:
Mapped "{[/users],methods=[GET]}" onto public
java.util.List<org.um.persistence.model.User>
org.um.web.controller.UserController.findAll(javax.servlet.http.HttpServletRequest)
So, it looks like it is mapping correctly, but when I hit it using the Rest >Client tool add on in Firefox, I get the following when doing a "GET" on the >following url: http://localhost:8082/api/users using Content-Type: application/json in my header .
What is going on? Very confused.
You should put a #RequestMapping("/api") on you class, and a #RequestMapping("/users") on your method (that should preferably return something to the client).
This ways your endpoint will be exposed as /api/users and you will be able to easily add further endpoints under /api/* into this class.

Resources