在实现了大约20个rest控制器和服务后,我发现自己的很多代码都是重复的,所以我想出了这个巧妙的设计。
CrudController.java包app.controllers;
import org.springframework.data.repository.CrudRepository;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import app.models.Model;
import app.services.CrudService;
@RestController
public abstract class CrudController<M extends Model, S extends CrudService<M, ? extends CrudRepository<M,Long>>> {
S service;
public abstract void setService(S service);
public abstract Boolean isAuthorized(Long entityId, S service);
@RequestMapping(value="/create", method = RequestMethod.POST)
public M create(M object) {
if(isAuthorized(object.getId(), service)) {
return service.save(object);
}
logUnauthorizedAccess();
return null;
}
@RequestMapping(value="/update", method = RequestMethod.POST)
public M update(M object) {
if(isAuthorized(object.getId(), service)) {
return service.update(object);
}
logUnauthorizedAccess();
return null;
}
@RequestMapping(value="/delete", method = RequestMethod.POST)
public Boolean delete(Long id) {
if(isAuthorized(id, service)) {
return service.delete(id);
}
logUnauthorizedAccess();
return null;
}
@RequestMapping(value="/get", method = RequestMethod.GET)
public @ResponseBody M get(Long id) {
if(isAuthorized(id, service)) {
return service.get(id);
}
logUnauthorizedAccess();
return null;
}
@RequestMapping(value="/json", method = RequestMethod.GET)
public @ResponseBody Iterable<M> json(ModelMap map) {
return service.getAll();
}
private void logUnauthorizedAccess() {
System.out.println("!!UN-AUTHORIZED ACCESS DETECTED!!");
}
}CrudService.java
package app.services;
import org.springframework.data.repository.CrudRepository;
public abstract class CrudService<M extends app.models.Model, R extends CrudRepository<M, Long>> {
R repo;
public abstract void setRepo(R repo);
/**
* Define the parameters that you want to save to the DB when calling the update() method
* @param from source object
* @param to DB object that gets saves, "return to" in this method
* @return
*/
public abstract M copy(M from, M to);
public Iterable<M> getAll() {
return this.repo.findAll();
}
/**
* Mainly used to create a new entity
* however, can also be used to save something without using the
* update() method.
* @param model
* @return saved entity model
*/
public M save(M model) {
return this.repo.save(model);
}
public M get(Long id) {
return this.repo.findOne(id);
}
public M update(M model) {
M updated = this.repo.findOne(model.getId());
updated = copy(model, updated);
return this.repo.save(updated);
}
public Boolean delete(Long id) {
this.repo.delete(id);
return true;
}
}Model.java
package app.models;
import java.sql.Timestamp;
import java.util.Date;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import javax.persistence.Version;
@MappedSuperclass
public abstract class Model {
@GeneratedValue
@Id
private Long id;
private Date dateCreated;
@Version
private Timestamp dateModified;
@PrePersist
void createdAt() {
this.setDateCreated(new Date());
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
public Timestamp getDateModified() {
return dateModified;
}
public void setDateModified(Timestamp dateModified) {
this.dateModified = dateModified;
}
}现在,我所有的控制器在给我的时候看起来都像下面这样。/create /get /update /delete /json
package app.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import app.models.Sample;
import app.services.SampleService;
@RestController
@RequestMapping("/sample")
public class SampleController extends CrudController<Sample, SampleService> {
@Autowired
@Override
public void setService(SampleService service) {
this.service = service;
}
@Override
public Boolean isAuthorized(Long entityId, SampleService service) {
return true;
}
}https://github.com/ddalcu/spring-starter/commit/27fb2a0719c4780d7cf648852d93b8fd3d8759c8
你们觉得怎么样,好的坏的,更好的方法?
发布于 2015-05-23 15:12:08
你应该看看Spring Data REST。
发布于 2015-05-23 14:59:47
Spring能够处理泛型:
只要其中的实现没有改变,您就不需要为每个Model创建CrudController的子类。
例如,您可以使用一个使用类的PathVariable的控制器。
那么你对CrudService和Dao也有同样的可能性。
如果您现在看到,对于某些实体,您需要在此控制器(或服务,dao)中进行特殊处理,那么至少有两种我所知道的方法:
第二层或第三层中的这种分叉主要取决于您需要在哪里拥有特殊的可能性。
我已经看到了这两种方法,目前我自己在spring项目中使用了这两种方法的混合。由于dispatcher servlet根据您拥有的变量数量对请求映射进行排序,因此很容易创建一个更具体的映射,只需使用专用控制器的path变量对该部分进行硬编码即可。
https://stackoverflow.com/questions/30408227
复制相似问题