首页 > 解决方案 > 内存和数据库服务调用是否应该在 (MVC)Controller 中完成?

问题描述

我的功能问题包括一些小细节,例如:

Recipe newRecipe = new Recipe()
newRecipe.setThing1(fromViewRecipe.getSubmittedData())
.
.
.

Recipe savedRecipe = recipeService.saveToDb(...)
recipeService.addRecipeToArrayList(savedRecipe);

是需要处理大量的细节和重复代码。但是我见过的每个教程都让人们用这些细节丰富的东西来加载他们的控制器。

完全删除这些东西并保留在您的服务层中不是最好的吗?

我是否正确遵循 MVC?

控制器

 @GetMapping(Mappings.HOME)
    public String getHomeView(Model model) {    // Took out params and attribs since they dont exist in the model
                                                // until the controller creates them

        log.info("Inside getMainView");


        Recipe recipe = svc.initNewRecipe(); // Create and initialize a new recipe


        model.addAttribute(AttributeNames.RECIPE, recipe);
        model.addAttribute(AttributeNames.RECIPE_ID, recipe.getRecipeId()); // should I put 0 here or what LOL
        model.addAttribute(AttributeNames.RECIPE_NAME, recipe.getRecipeName()); // "" ?
        model.addAttribute(AttributeNames.RECIPE_DATA, recipeData());

        log.info("recipe ingredient list size: {}", recipe.getIngredientList().size());
        //model.addAttribute(AttributeNames.INGREDIENT_LIST, recipe.getIngredientList());

        return ViewNames.HOME;
    }

服务

    @Slf4j
@Service
public class RecipeServiceImpl implements RecipeService{


    @Value("${id.length}")
    private int idLength;

    @Autowired
    private RecipeRepository recipeRepository;

    @Autowired
    IDManager idManager;

    @Autowired
    List<Recipe> inMemRecipeList = new ArrayList<>();  // In-memory list of recipes


    // Get all Recipes from DB and return ArrayList of Recipes
    @Override
    public List<Recipe> getAllRecipes() {

        // Retrieve recipes from DB and add to In-memory list
        for(RecipeEntity recipeDbEntity : recipeRepository.findAll()){

            Recipe recipe = new Recipe();
            BeanUtils.copyProperties(recipeDbEntity, recipe);
            inMemRecipeList.add(recipe);
        }


        log.info("Returning list from getAllRecipes : {}", inMemRecipeList);
        return inMemRecipeList;
    }


    @Override
    public Recipe addRecipeToInMemList(Recipe newRecipe){

        getAllRecipes().add(newRecipe); // Add to in memory list
    }


    // Save a recipe and log
    @Override
    public RecipeEntity addRecipeToDb(RecipeEntity recipeToSave) {



        log.info("Saved recipe with ID: " + savedRecipe.getRecipeId());

        return recipeRepository.save(recipeToSave);
    }


    // == Create new blank Recipe, save to DB and memory and return ==

    public Recipe initNewRecipe(){

        // Create a new recipe
        Recipe newRecipe = new Recipe();

        // Create a list for the ingredients,
        // add a blank ingredient FOR TESTING to the list
        // attach the list to the Recipe
        List<Ingredient> ingredientList = new ArrayList<>();

        Ingredient blankIngredient = new Ingredient(
                0,
                0.0,
                Unit.CUPS,
                ""
        );

        ingredientList.add(blankIngredient);
        newRecipe.setIngredientList(ingredientList);


        // Save it to DB and return the result
        RecipeEntity newRecipeEntity = new RecipeEntity();
        BeanUtils.copyProperties(newRecipe, newRecipeEntity);

        Recipe returnableRecipe = new Recipe();
        addRecipeToInMemList(BeanUtils.copyProperties(addRecipeToDb(newRecipeEntity), returnableRecipe);

        return newRecipe;
    }

.
.
.

标签: springmodel-view-controller

解决方案


In my opinion, yes controller should only have code that is responsible for rendering of view. Any logic or calculations should go to service layer.

One clear benefit of having this separation is when you move out your legacy implementation and starts providing APIs to new js frameworks or other clients, your service layer will still be valid. All you will be required to create is RESTController.

As per Wikipedia, this pattern is designed for code reusability and parallel development. So before creating java classes one must consider separation of concerns, single responsibility and KISS principles. These principles advice to make your classes or method simple and fulfiling only a single responsibility.

This Microsoft Document (though not for Java) indicates what your controller should be.

Service layer in my opinion is part of model. Regarding your question about correct implementation, I suggget moving as much to service layer. You are adding some of the model attributes in your controller, ask yourself

  • if it is necessary to have these attributes here.
  • why is your model attributes not present in your model definition that you are retrieving from service. e.g. I will again give example of legacy system, which when you change to Rest, will those attributes not be required in your Rest Apis? If the answer is 'yes required' why not move these to service layers.

推荐阅读