Development of dish management module--Teach you how to do ssm+springboot entry back-end project dark horse programmer Ruiji takeaway (5)


foreword

In order to consolidate the knowledge learned, the author tried to start publishing some blogs of learning notes for future review. Of course, it would be great if it could help some newcomers learn new technologies. The author is a piece of food. If there are any mistakes in the records in the article, readers and friends are welcome to criticize and correct.
(The reference source code of the blog can be found in the resources on my homepage. If you have any questions during the learning process, please feel free to ask me in the comment area)

1. File upload and download

1. Introduction to file upload

  • File upload, also known as upload, refers to the process of uploading local pictures, videos, audios and other files to the server, which can be browsed or downloaded by other users
  • File upload is widely used in projects. We often use the file upload function in Weibo and WeChat Moments
  • When uploading files, the form form of the page has the following requirements
  1. method="post" ---- use the post method to submit data
  2. enctype="multipart/form-data" ---- upload files in multipart format
  3. type="file" ---- use the input file control to upload
  4. example
<form method="post" action="/common/upload" enctype="multipart/form-data">
<input name="myFile" type="file"/>
<input type="submit" value="提交"/>
</form>
  • At present, some front-end component libraries also provide corresponding upload components, but the underlying principle is still form-based file upload, such as the upload upload component provided in ElementUl

insert image description here

  • To receive the files uploaded by the client page, the server usually uses two components of Apache:
  1. commons-fileupload
  2. commons-io
  • The Spring framework encapsulates the file upload in the spring-web package, which greatly simplifies the server code. We only need to declare a parameter of type MultipartFile in the Controller method to receive the uploaded file, for example

insert image description here

2. File download introduction

  • File downloading, also known as downloading, refers to the process of transferring files from a server to a local computer.
  • There are usually two forms of file download through the browser:
  1. Download as an attachment, pop up a save dialog box, and save the file to the specified disk directory
  2. open directly in the browser
  • Downloading files through the browser is essentially the process of the server writing the file back to the browser in the form of a stream

3. Realize the file upload function

1. Front-end related code analysis

insert image description here
2. To facilitate debugging, add the common/ path to the filter

 //定义不需要处理的请求路径
        String[] urls = new String[]{
    
    
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**",
                "/common/**"
        };

3. Specify the upload path in the application.yml file

reggie:
  path: D:\img\

4. Create a new controller and write related methods

/**
 * 文件上传和下载
 */
@RestController
@RequestMapping("/common")
@Slf4j
public class CommonController {
    
    

    @Value("${reggie.path}")
    private String basePath;

    /**
     * 文件上传
     * @param file
     * @return
     */
    @PostMapping("/upload")
    public R<String> upload(MultipartFile file){
    
    
        //file是一个临时文件,需要转存到指定位置,否则本次请求完成后临时文件会删除
        log.info(file.toString());

        //原始文件名
        String originalFilename = file.getOriginalFilename();//abc.jpg
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

        //使用UUID重新生成文件名,防止文件名称重复造成文件覆盖
        String fileName = UUID.randomUUID().toString() + suffix;//dfsdfdfd.jpg

        //创建一个目录对象
        File dir = new File(basePath);
        //判断当前目录是否存在
        if(!dir.exists()){
    
    
            //目录不存在,需要创建
            dir.mkdirs();
        }

        try {
    
    
            //将临时文件转存到指定位置
            file.transferTo(new File(basePath + fileName));
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        return R.success(fileName);
    }
}

4. Realize the file download function

1. Front-end related code analysis

For file download, you can use tags to display the downloaded pictures on the page side

insert image description here

  • Write the code for the download method in the controller
/**
     * 文件下载
     * @param name
     * @param response
     */
    @GetMapping("/download")
    public void download(String name, HttpServletResponse response){
    
    

        try {
    
    
            //输入流,通过输入流读取文件内容
            FileInputStream fileInputStream = new FileInputStream(new File(basePath + name));

            //输出流,通过输出流将文件写回浏览器
            ServletOutputStream outputStream = response.getOutputStream();

            response.setContentType("image/jpeg");

            int len = 0;
            byte[] bytes = new byte[1024];
            while ((len = fileInputStream.read(bytes)) != -1){
    
    
                outputStream.write(bytes,0,len);
                outputStream.flush();
            }

            //关闭资源
            outputStream.close();
            fileInputStream.close();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }

    }

5. Upload and download picture effect preview

insert image description here

2. New dishes

1. Demand analysis

The background system can manage dish information, and add a new dish through the new function. When adding a dish, you need to select the dish category to which the current dish belongs and upload the dish picture. The corresponding dish information will be displayed according to the dish classification on the mobile terminal.

insert image description here

2. Data model

  • Adding a new dish is actually inserting the dish information entered on the new page into the dish table. If you add a flavor method, you also need to insert data into the dish flavor table. So when adding a new dish, two tables are involved:
  1. dish ---- dish list
  2. dish flavor ---- dish taste table

insert image description here

insert image description here

3. Code development

1. Before developing business functions, first create the basic structure of classes and interfaces that need to be used

  • Entity class DishFlavor
/**
菜品口味
 */
@Data
public class DishFlavor implements Serializable {
    
    

    private static final long serialVersionUID = 1L;

    private Long id;


    //菜品id
    private Long dishId;


    //口味名称
    private String name;


    //口味数据list
    private String value;


    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;


    @TableField(fill = FieldFill.INSERT)
    private Long createUser;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;


    //是否删除
    private Integer isDeleted;

}
  • Mapper interface DishFlavorMapper
@Mapper
public interface DishFlavorMapper extends BaseMapper<DishFlavor> {
    
    
}
  • Business layer interface DishFlavorService
public interface DishFlavorService extends IService<DishFlavor> {
    
    
}

  • Business layer implementation class DishFlavorServicelmpl
@Service
public class DishFlavorServiceImpl extends ServiceImpl<DishFlavorMapper,DishFlavor> implements DishFlavorService {
    
    
}
  • Control layer DishController
/**
 * 菜品管理
 */
@RestController
@RequestMapping("/dish")
@Slf4j
public class DishController {
    
    
     @Autowired
    private DishService dishService;

    @Autowired
    private DishFlavorService dishFlavorService;
}

2. Before developing the code, it is necessary to sort out the interaction process between the front-end page and the server when adding new dishes

  1. The page (backend/page/food/add.html) sends an ajax request to request the server to obtain the dish classification data and display it in the drop-down box
  2. The page sends a request for image upload, and requests the server to save the image to the server
  3. The page sends a request to download the image, and echoes the uploaded image
  4. Click the save button, send an ajax request, and submit the dish-related data to the server in the form of ison
  5. To develop the function of adding new dishes is actually to write code on the server side to process the 4 requests sent by the front-end page

3. Query data according to conditions (CategoryController)

/**
     * 根据条件查询分类数据
     * @param category
     * @return
     */
    @GetMapping("/list")
    public R<List<Category>> list(Category category){
    
    
        //条件构造器
        LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
        //添加条件
        queryWrapper.eq(category.getType() != null,Category::getType,category.getType());
        //添加排序条件
        queryWrapper.orderByAsc(Category::getSort).orderByDesc(Category::getUpdateTime);

        List<Category> list = categoryService.list(queryWrapper);
        return R.success(list);
    }

4. Front-end related page analysis
insert image description here

5. Create and write DishDto, which is used to encapsulate the data submitted by the page

DTO, the full name is Data Transfer object, that is, data transfer object, which is generally used for data transfer between the presentation layer and the service layer (not one-to-one correspondence with the database table)

@Data
public class DishDto extends Dish {
    
    
    //接收模拟提交数据中的flavors参数
    private List<DishFlavor> flavors = new ArrayList<>();

    private String categoryName;

    private Integer copies;
}

6. In DishService interface method

public interface DishService extends IService<Dish> {
    
    

    //新增菜品,同时插入菜品对应的口味数据,需要操作两张表:dish、dish_flavor
    public void saveWithFlavor(DishDto dishDto);
}

7. Concrete implementation class

@Service
@Slf4j
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
    
    
    @Autowired
    private DishFlavorService dishFlavorService;

    /**
     * 新增菜品,同时保存对应的口味数据
     * @param dishDto
     */
    @Transactional
    public void saveWithFlavor(DishDto dishDto) {
    
    
        //保存菜品的基本信息到菜品表dish
        this.save(dishDto);

        Long dishId = dishDto.getId();//菜品id

        //菜品口味
        List<DishFlavor> flavors = dishDto.getFlavors();
        flavors = flavors.stream().map((item) -> {
    
    
            item.setDishId(dishId);
            return item;
        }).collect(Collectors.toList());

        //保存菜品口味数据到菜品口味表dish_flavor
        dishFlavorService.saveBatch(flavors);

    } 
}

4. Functional testing

  1. Query data according to conditions
    insert image description here
    2. Realize the save function

insert image description here

insert image description here

3. Paging query of dish information

1. Demand analysis

When there is a lot of dish data in the system, it will be messy if all of them are displayed on one page, and it is not easy to view. Therefore, in general systems, the list data will be displayed in a page-by-page manner.

insert image description here

2. Code development

  1. Before developing the code, it is necessary to sort out the interaction process between the front-end page and the server when the dishes are paged and queried
  1. The page (backend/page/food/list.html) sends an ajax request, submits the paging query parameters (page, pageSize, name) to the server, and obtains the paging data
  2. The page sends a request to request the server to download the image for page image display
  3. To develop the page-by-page query function of dish information is actually to write code on the server side to process the two requests sent by the front-end page.

2. Develop the corresponding Controller method

 /**
     * 菜品信息分页查询
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    public R<Page> page(int page,int pageSize,String name){
    
    

        //构造分页构造器对象
        Page<Dish> pageInfo = new Page<>(page,pageSize);
        Page<DishDto> dishDtoPage = new Page<>();

        //条件构造器
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        //添加过滤条件
        queryWrapper.like(name != null,Dish::getName,name);
        //添加排序条件
        queryWrapper.orderByDesc(Dish::getUpdateTime);

        //执行分页查询
        dishService.page(pageInfo,queryWrapper);

        //对象拷贝
        BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");

        List<Dish> records = pageInfo.getRecords();

        List<DishDto> list = records.stream().map((item) -> {
    
    
            DishDto dishDto = new DishDto();

            BeanUtils.copyProperties(item,dishDto);

            Long categoryId = item.getCategoryId();//分类id
            //根据id查询分类对象
            Category category = categoryService.getById(categoryId);

            if(category != null){
    
    
                String categoryName = category.getName();
                dishDto.setCategoryName(categoryName);
            }
            return dishDto;
        }).collect(Collectors.toList());

        dishDtoPage.setRecords(list);

        return R.success(dishDtoPage);
    }

3. Functional testing

insert image description here

4. Modify the dishes

1. Demand analysis

Click the modify button on the dish management list page to jump to the modify dish page, echo the relevant information of the dish on the modify page and modify it, and finally click the OK button to complete the modification operation

insert image description here

2. Code development

1. Before developing the code, it is necessary to sort out the interaction process between the front-end page (add.html) and the server when modifying dishes

  1. The page sends an ajax request to request the server to obtain classification data, which is used for data display in the dish classification drop-down box
  2. The page sends an ajax request to request the server to query the current dish information according to the id, which is used to echo the dish information
  3. The page sends a request to request the server to download the image, which is used for page image echo
  4. Click the save button, the page sends an ajax request, and submits the modified dish-related data to the server in the form of json
  5. The function of developing and modifying dishes is actually to write code on the server side to process the 4 requests sent by the front-end page

2. Write query methods and interface methods for updating dishes in DishService

public interface DishService extends IService<Dish> {
    
    
    //...
    //根据id查询菜品信息和对应的口味信息
    public DishDto getByIdWithFlavor(Long id);

    //更新菜品信息,同时更新对应的口味信息
    public void updateWithFlavor(DishDto dishDto);
}

3. Implementation class implementation

public class DishServiceImpl extends ServiceImpl<DishMapper,Dish> implements DishService {
    
    

    @Autowired
    private DishFlavorService dishFlavorService;

    /**
     * 新增菜品,同时保存对应的口味数据
     * @param dishDto
     */
    @Transactional
    public void saveWithFlavor(DishDto dishDto) {
    
    
        //保存菜品的基本信息到菜品表dish
        this.save(dishDto);

        Long dishId = dishDto.getId();//菜品id

        //菜品口味
        List<DishFlavor> flavors = dishDto.getFlavors();
        flavors = flavors.stream().map((item) -> {
    
    
            item.setDishId(dishId);
            return item;
        }).collect(Collectors.toList());

        //保存菜品口味数据到菜品口味表dish_flavor
        dishFlavorService.saveBatch(flavors);

    }

    /**
     * 根据id查询菜品信息和对应的口味信息
     * @param id
     * @return
     */
    public DishDto getByIdWithFlavor(Long id) {
    
    
        //查询菜品基本信息,从dish表查询
        Dish dish = this.getById(id);

        DishDto dishDto = new DishDto();
        BeanUtils.copyProperties(dish,dishDto);

        //查询当前菜品对应的口味信息,从dish_flavor表查询
        LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DishFlavor::getDishId,dish.getId());
        List<DishFlavor> flavors = dishFlavorService.list(queryWrapper);
        dishDto.setFlavors(flavors);

        return dishDto;
    }

    @Override
    @Transactional
    public void updateWithFlavor(DishDto dishDto) {
    
    
        //更新dish表基本信息
        this.updateById(dishDto);

        //清理当前菜品对应口味数据---dish_flavor表的delete操作
        LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(DishFlavor::getDishId,dishDto.getId());

        dishFlavorService.remove(queryWrapper);

        //添加当前提交过来的口味数据---dish_flavor表的insert操作
        List<DishFlavor> flavors = dishDto.getFlavors();

        flavors = flavors.stream().map((item) -> {
    
    
            item.setDishId(dishDto.getId());
            return item;
        }).collect(Collectors.toList());

        dishFlavorService.saveBatch(flavors);
    }
}

4. Write the corresponding query method and modification method in the controller

/**
     * 根据id查询菜品信息和对应的口味信息
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public R<DishDto> get(@PathVariable Long id){
    
    

        DishDto dishDto = dishService.getByIdWithFlavor(id);

        return R.success(dishDto);
    }

    /**
     * 修改菜品
     * @param dishDto
     * @return
     */
    @PutMapping
    public R<String> update(@RequestBody DishDto dishDto){
    
    
        log.info(dishDto.toString());

        dishService.updateWithFlavor(dishDto);

        return R.success("新增菜品成功");
    }

3. Functional testing

insert image description here

Summarize

Everyone is welcome to leave a message for exchange and criticism. If the article is helpful to you or you think the author's writing is not bad, you can click to follow, like, and bookmark to support.
(The reference source code of the blog can be found in the resources on my homepage. If you have any questions during the learning process, please feel free to ask me in the comment area)

Guess you like

Origin blog.csdn.net/HHX_01/article/details/131761647