首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在spring-framework中实现20 @RestController的最好方法而不重复自己(DRY)

在spring-framework中实现20 @RestController的最好方法而不重复自己(DRY)
EN

Stack Overflow用户
提问于 2015-05-23 10:16:02
回答 2查看 2.1K关注 0票数 1

在实现了大约20个rest控制器和服务后,我发现自己的很多代码都是重复的,所以我想出了这个巧妙的设计。

CrudController.java包app.controllers;

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

你们觉得怎么样,好的坏的,更好的方法?

EN

回答 2

Stack Overflow用户

发布于 2015-05-23 15:12:08

你应该看看Spring Data REST

票数 4
EN

Stack Overflow用户

发布于 2015-05-23 14:59:47

Spring能够处理泛型:

只要其中的实现没有改变,您就不需要为每个Model创建CrudController的子类。

例如,您可以使用一个使用类的PathVariable的控制器。

那么你对CrudServiceDao也有同样的可能性。

如果您现在看到,对于某些实体,您需要在此控制器(或服务,dao)中进行特殊处理,那么至少有两种我所知道的方法:

  • 使用控制器、服务和dao为此实体类型创建一个完整的新路由。
  • 不是简单地使用crudcontroller中的crudservice,而是自动生成一个列表(或映射)并查找正确的服务以继续路由。

第二层或第三层中的这种分叉主要取决于您需要在哪里拥有特殊的可能性。

我已经看到了这两种方法,目前我自己在spring项目中使用了这两种方法的混合。由于dispatcher servlet根据您拥有的变量数量对请求映射进行排序,因此很容易创建一个更具体的映射,只需使用专用控制器的path变量对该部分进行硬编码即可。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30408227

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档