首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用弹簧引导的REST设计

使用弹簧引导的REST设计
EN

Code Review用户
提问于 2017-11-08 18:20:20
回答 1查看 775关注 0票数 0

下面的API适用于对用户的CRUD操作及其相应的过滤器(某种规则)。这些过滤器基于用户对来自不同来源的传入数据应用,然后对数据进行各种转换。

我希望评审人员对设计、端点、异常处理和请求/响应进行评论。由于我正在学习设计REST,您的评论将有助于我在将来编写更好的API。

Data.class创建一个用户对象的静态列表,所有CRUD操作都在这个对象上执行,并从/到文件序列化/反序列化。

选择一个文件到DB的原因是现在数据非常小,而且项目正处于POC阶段。

代码语言:javascript
复制
package com.cisco.daas.filter.services;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.cisco.daas.configservice.entities.User;
import com.cisco.daas.configservice.utilities.FileOperations;
import com.cisco.daas.configservice.utilities.Operations;

public class Data {

    private static final Operations<User> operations = new FileOperations<User>();

    private static final List<User> users = new ArrayList<>();

    public static List<User> getUsers() {
        users.clear();
        try {
            users.addAll(operations.get());
        } catch (IOException e) {
            e.getMessage();
        }
        return users;
    }
}

接口:注释一次创建实体列表的方法的原因是因为我觉得它不优雅。如果想法不对,请告诉我。

代码语言:javascript
复制
package com.cisco.daas.filter.services;

import java.util.List;

import com.cisco.daas.configservice.entities.Filter;

public interface IFilterService {

    void add(String userName,Filter filter);

    //void add(String userName,List<Filter> filters);

    Filter update(String userName, Filter filter);

    void remove(String userName, String filterName);

    List<Filter> getAll(String userName);

    Filter getOne(String userName,String filterName); 

}


package com.cisco.daas.filter.services;

import java.util.List;

import com.cisco.daas.configservice.entities.User;

public interface IUserService {

    User add(User item);

    //List<User> add(List<User> items);

    User update(User item);

    String remove(String userID);

    List<User> query(String userID);

    List<User> query();

}

实现:

代码语言:javascript
复制
package com.cisco.daas.filter.services;

import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.cisco.daas.configservice.entities.Filter;
import com.cisco.daas.configservice.entities.User;
import com.cisco.daas.configservice.utilities.FileOperations;
import com.cisco.daas.configservice.utilities.Operations;

@Service
public class FilterService implements IFilterService {

    private List<User> users = Data.getUsers();
    private static final Operations<User> operations = new FileOperations<User>();

    public FilterService() {

    }

    public void add(String userID, Filter filter) {
        users.stream().filter(u -> u.getUserId().equals(userID)).forEach(x -> {
            x.getFilters().add(filter);
        });

        try {
            operations.save(users);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

//  public void add(String userID, List<Filter> filters) {
//      users.stream().filter(u -> u.getUserId().equals(userID)).forEach(x -> {
//          x.getFilters().addAll(filters);
//      });
//
//      try {
//          operations.save(users);
//      } catch (IOException e) {
//          // TODO Auto-generated catch block
//          e.printStackTrace();
//      }
//
//  }

    public Filter update(String userID, Filter filter) {
        users.stream().filter(element -> element.getUserId().equals(userID) && element.getFilters().stream()
                .filter(f -> f.getName().equals(filter.getName())).findAny().isPresent()).forEach(x -> {
                    x.getFilters().stream().forEach(s -> {
                        s.setCreatedOn(filter.getCreatedOn());
                        s.setDescription(filter.getDescription());
                        s.setEnabled(filter.isEnabled());
                        s.setFilterValue(filter.getFilterValue());
                        s.setReadOnly(filter.isReadOnly());
                        s.setModifiedOn(filter.getModifiedOn());
                        s.setName(filter.getName());
                        s.setType(filter.getType());
                        s.setValid(filter.isValid());
                        s.setEncrypted(filter.isEncrypted());
                    });
                });

        try {
            operations.save(users);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return filter;
    }

    public void remove(String userID, String filterName) {
        users.removeIf(element -> element.getUserId().equals(userID) && element.getFilters().stream()
                .filter(f -> f.getName().equals(filterName)).findAny().isPresent());

        try {
            operations.save(users);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public List<Filter> getAll(String userID) {
        List<Filter> filters = users.stream().map(User::getFilters).flatMap(List::stream).distinct()
                .collect(Collectors.toList());
        return filters;
    }

    public Filter getOne(String userID, String filterName) {
        java.util.function.Predicate<Filter> pred = p -> p.getName().equals(filterName);
        List<Filter> filters = users.stream().map(User::getFilters).flatMap(List::stream).distinct()
                .collect(Collectors.toList());
        Optional<Filter> f = filters.stream().filter(pred).findFirst();
        return f.get();
    }

}
package com.cisco.daas.filter.services;

import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.cisco.daas.configservice.entities.Filter;
import com.cisco.daas.configservice.entities.User;
import com.cisco.daas.configservice.utilities.FileOperations;
import com.cisco.daas.configservice.utilities.Operations;

@Service
public class UserService implements IUserService {

    private List<User> users = Data.getUsers();
    private static final Operations<User> operations = new FileOperations<User>();

    public UserService() {
    }

    public User add(User item) {

        Optional<User> result = users.stream().filter(x -> item.getUserId().equals(x.getUserId())).findFirst();
        if (!result.isPresent() || result == null) {

            users.add(item);
            for (User user : users) {
                try {
                    operations.save(user);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else {
            System.out.println("User already exist");
        }
        return item;
    }

//  public List<User> add(List<User> items) {
//      Set<String> userids = items.stream().map(x -> x.getUserId()).collect(Collectors.toSet());
//      List<User> present = users.stream().filter(x -> userids.contains(x.getUserId())).collect(Collectors.toList());
//      List<User> notPresent = users.stream().filter(x -> !userids.contains(x.getUserId()))
//              .collect(Collectors.toList());
//
//      if (present.isEmpty()) {
//          users.addAll(items);
//          try {
//              operations.save(users);
//          } catch (IOException e) {
//              e.printStackTrace();
//          }
//      } else if (!notPresent.isEmpty()) {
//          users.addAll(notPresent);
//          try {
//              operations.save(users);
//          } catch (IOException e) {
//              e.printStackTrace();
//          }
//      }
//      return items;
//
//  }

    public User update(User item) {
        users.forEach(element -> {
            if (element.getUserId() == item.getUserId()) {
                element.setUserId(item.getUserId());
                element.setUserName(item.getUserName());
                element.getFilters().forEach(filter -> {
                    Set<String> filters = item.getFilters().stream().map(f -> f.getName()).collect(Collectors.toSet());
                    List<Filter> present = item.getFilters().stream().filter(x -> filters.contains(x.getName()))
                            .collect(Collectors.toList());
                    List<Filter> notPresent = item.getFilters().stream().filter(x -> !filters.contains(x.getName()))
                            .collect(Collectors.toList());
                    if (present.isEmpty()) {
                        element.setFilters(item.getFilters());
                    } else {
                        element.getFilters().stream().forEach(filt -> {
                            present.stream().forEach(x -> {
                                if (filt.getName() == x.getName()) {
                                    filt.setName(x.getName());
                                    filt.setFilterValue(x.getFilterValue());
                                    filt.setCreatedOn(x.getCreatedOn());
                                    filt.setModifiedOn(x.getModifiedOn());
                                    filt.setEnabled(x.isEnabled());
                                    filt.setEncrypted(x.isEncrypted());
                                    filt.setReadOnly(x.isReadOnly());
                                    filt.setType(x.getType());
                                    filt.setValid(x.isValid());
                                    filt.setDescription(x.getDescription());
                                }
                            });
                        });
                    }

                    if (!notPresent.isEmpty()) {
                        element.setFilters(notPresent);
                    }
                });
            }
        });

        try {
            operations.save(users);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return item;
    }

    public String remove(String userID) {
        users.removeIf(x -> x.getUserId().equals(userID));
        try {
            operations.save(users);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return userID;
    }

    public List<User> query(String userID) {
        List<User> result = null;
        if (userID == null) {
            System.out.println("User ID cannot be empty");
        } else {
            result = users.stream().filter(e -> e.getUserId().equals(userID)).collect(Collectors.toList());
        }
        return result;
    }

    public List<User> query() {
        return users;
    }

}

对文件执行操作的实用程序类,如序列化/反序列化JSON:

代码语言:javascript
复制
package com.cisco.daas.configservice.utilities;

import java.io.IOException;
import java.util.List;

public interface Operations<T> {

    void save(T serializableObject) throws IOException;
    void save(List<T> serializableObjects) throws IOException;
    List<T> get() throws IOException;

}


package com.cisco.daas.configservice.utilities;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.cisco.daas.configservice.entities.User;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;

public class FileOperations<T> implements Operations<T> {

    private ObjectMapper objectMapper;
    // this is going to come from the property file.
    private String filePath = "C:\\Users\\phyadavi\\workspace\\ConfigurationService\\src\\main\\resources\\seed.txt";
    private File file;
    // private T targetClass;

    public FileOperations() {
        this.objectMapper = new ObjectMapper();
        this.file = new File(filePath);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.getMessage();
            }
        }
    }

    private void saveImpl(Object serializableObject) throws IOException {
        String jsonData = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(serializableObject);
        BufferedWriter br = new BufferedWriter(new FileWriter(file));
        br.write(jsonData);
        br.close();
    }

    @Override
    public void save(List<T> serializableObjects) throws IOException {
        saveImpl(serializableObjects);
    }

    @Override
    public void save(T serializableObject) throws IOException {
        saveImpl(serializableObject);
    }

    @Override
    public List<T> get() throws IOException {
        // JavaType type =
        // objectMapper.getTypeFactory().constructCollectionType(ArrayList.class,
        // targetClass.getClass());
        // List<T> list = objectMapper.readValue(file, type);
        List<T> list = objectMapper.readValue(file, new TypeReference<List<User>>() {
        });
        if (list == null) {
            List<T> list1 = new ArrayList<T>();
            return list1;
        }
        return list;
    }

}

实体:

代码语言:javascript
复制
package com.cisco.daas.configservice.entities;

import java.util.UUID;

public interface Entity {   
    String id = UUID.randomUUID().toString();
}


package com.cisco.daas.configservice.entities;

import java.util.List;

public class User implements Entity {

    public User() {
    }

    private String userName;
    private String userId;
    private List<Filter> filters;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public List<Filter> getFilters() {
        return filters;
    }

    public void setFilters(List<Filter> filters) {
        this.filters = filters;
    }

}


package com.cisco.daas.configservice.entities;

import java.util.Date;

public class Filter {

    private String name;
    private FilterValue value;
    private String type;
    private boolean encrypted;
    private boolean readOnly;
    private Date createdOn;
    private Date modifiedOn;
    private boolean valid;
    private boolean enabled;
    private String description;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public FilterValue getFilterValue() {
        return value;
    }

    public void setFilterValue(FilterValue value) {
        this.value = value;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public boolean isEncrypted() {
        return encrypted;
    }

    public void setEncrypted(boolean encrypted) {
        this.encrypted = encrypted;
    }

    public boolean isReadOnly() {
        return readOnly;
    }

    public void setReadOnly(boolean readOnly) {
        this.readOnly = readOnly;
    }

    public Date getCreatedOn() {
        return createdOn;
    }

    public void setCreatedOn(Date createdOn) {
        this.createdOn = createdOn;
    }

    public Date getModifiedOn() {
        return modifiedOn;
    }

    public void setModifiedOn(Date modifiedOn) {
        this.modifiedOn = modifiedOn;
    }

    public boolean isValid() {
        return valid;
    }

    public void setValid(boolean valid) {
        this.valid = valid;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

}


package com.cisco.daas.configservice.entities;

public class FilterValue {

    private String filterId;
    private String filterName;
    private Condition condition;
    private boolean action;

    public String getFilterId() {
        return filterId;
    }

    public void setFilterId(String filterId) {
        this.filterId = filterId;
    }

    public String getFilterName() {
        return filterName;
    }

    public void setFilterName(String filterName) {
        this.filterName = filterName;
    }

    public Condition getCondition() {
        return condition;
    }

    public void setCondition(Condition condition) {
        this.condition = condition;
    }

    public boolean isAction() {
        return action;
    }

    public void setAction(boolean action) {
        this.action = action;
    }
}


package com.cisco.daas.configservice.entities;

public class Condition {

    private String field;
    private Criteria criteria;
    private String value;
    private boolean isAdhering;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public Criteria getCriteria() {
        return criteria;
    }

    public void setCriteria(Criteria criteria) {
        this.criteria = criteria;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public boolean isAdhering() {
        return isAdhering;
    }

    public void setAdhering(boolean isAdhering) {
        this.isAdhering = isAdhering;
    }
}


package com.cisco.daas.configservice.entities;

public enum Criteria {

    IS, 
    CONTAINS, 
    GREATER_THAN, 
    LESSER_THAN;

}

管制员:

代码语言:javascript
复制
package com.cisco.daas.configservice.controller;

import java.util.List;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
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 org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

import com.cisco.daas.configservice.entities.User;
import com.cisco.daas.filter.services.IUserService;

@RestController
@RequestMapping("/api")
public class UserController {

    @Autowired
    private IUserService userService;

    @RequestMapping(value = "/users", method = RequestMethod.GET)
    public @ResponseBody List<User> getAll() {
        return userService.query();
    }

    @RequestMapping(value = "/users/{id}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
    public @ResponseBody List<User> getUser(@PathVariable(value = "id") String userid) {
        return userService.query(userid);
    }

    @RequestMapping(value = "/users", method = RequestMethod.POST, produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<HttpStatus> createUser(@Valid @RequestBody User user) {
        userService.add(user);
        return ResponseEntity.ok(HttpStatus.OK);
    }

//  @RequestMapping(value = "/users", method = RequestMethod.POST, produces = { MediaType.APPLICATION_JSON_VALUE })
//  public ResponseEntity<HttpStatus> createUsers(@Valid @RequestBody List<User> entities) {
//      @SuppressWarnings("unused")
//      List<User> users = userService.add(entities);
//      return ResponseEntity.ok(HttpStatus.OK);
//  }

    @RequestMapping(value = "/users", method = RequestMethod.PUT, produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<User> updateUser(@Valid @RequestBody User entity) {
        User user = userService.update(entity);
        if (user == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(user);
    }

    @RequestMapping(value = "/userid/{id}", method = RequestMethod.DELETE, produces = {
            MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<HttpStatus> deleteUser(@PathVariable(value = "id") String userid) {
        String result = userService.remove(userid);
        if (result.equals(null)) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(HttpStatus.OK);
    }

}


package com.cisco.daas.configservice.controller;

import java.util.List;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.cisco.daas.configservice.entities.Filter;
import com.cisco.daas.filter.services.IFilterService;

@RestController
@RequestMapping("/api")
public class FilterController {

    @Autowired
    private IFilterService filterService;

    @RequestMapping(value = "/users/{id}/filters", method = RequestMethod.GET, produces = {
            MediaType.APPLICATION_JSON_VALUE })
    public @ResponseBody List<Filter> getAll(@PathVariable(value = "id") String userID) {
        return filterService.getAll(userID);
    }

    @RequestMapping(value = "/users/{id}/filters/{filterName}", method = RequestMethod.GET, produces = {
            MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<Filter> getFilter(@RequestParam(value = "id", required = true) String userID,
            @PathVariable(value = "filterName") String filterName) {
        Filter filter = filterService.getOne(userID, filterName);
        if (filter == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(filter);
    }

    @RequestMapping(value = "/users/{id}/filters", method = RequestMethod.POST, produces = {
            MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<HttpStatus> createFilter(@PathVariable(value = "id") String id,
            @Valid @RequestBody Filter filter) {
        filterService.add(id, filter);
        return ResponseEntity.ok(HttpStatus.OK);
    }

//  @RequestMapping(value = "/users/{userID}/filters", method = RequestMethod.POST, produces = {
//          MediaType.APPLICATION_JSON_VALUE })
//  public ResponseEntity<HttpStatus> createFilters(@PathVariable(value = "id") String userID,
//          @Valid @RequestBody List<Filter> filters) {
//      filterService.add(userID, filters);
//      return ResponseEntity.ok(HttpStatus.OK);
//  }

    @RequestMapping(value = "/users/{userID}/filters", method = RequestMethod.PUT, produces = {
            MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<Filter> updateUser(@PathVariable(value = "id") String userID,
            @Valid @RequestBody Filter entity) {
        Filter filter = filterService.update(userID, entity);
        if (filter == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(filter);
    }

    @RequestMapping(value = "/userid/{id}/filters/{filterName}", method = RequestMethod.DELETE, produces = {
            MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<HttpStatus> deleteUser(@PathVariable(value = "id") String userid,
            @PathVariable(value="filterName") String filterName) {
        filterService.remove(userid, filterName);
        return ResponseEntity.ok(HttpStatus.OK);
    }
}

主修班:

代码语言:javascript
复制
package com.cisco.daas;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages="com.cisco.daas")
public class ConfigurationServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigurationServiceApplication.class, args);
    }
}
EN

回答 1

Code Review用户

发布于 2017-11-08 19:18:25

我希望这属于你所要求的设计领域。这些是我唯一能想到的建议。对于您的端点或异常处理,我没有真正有用的评论,因为它们看起来非常简单,而且我认为没有什么问题。

我建议用构造函数注入代替字段自动加载。而不是:

代码语言:javascript
复制
@Autowired
private IFilterService filterService;

用途:

代码语言:javascript
复制
private final IFilterService filterService;

@Autowired
public FilterController (IFilterService filterService) {
    this.filterService = filterService;
}

这里解释了这一点:http://olivergierke.de/2013/11/why-field-injection-is-evil/

您还可以将@RequestMapping(method = RequestMethod.PUT)替换为@PutMapping,因为即时查看使用的是哪种方法要容易一些,尽管两者的工作原理完全相同。

我建议查看https://projectlombok.org/,让自己添加类级注释(如@Getter @Setter ),并保存一些样板代码。它还有很多其他的功能,网站有更多的信息。(注意:据我所知,JDK9仍然不受支持)

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

https://codereview.stackexchange.com/questions/179942

复制
相关文章

相似问题

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