瑞吉外卖项目详细总结

文章目录

  • 瑞吉外卖
    • 1.技术栈
    • 2.项目文件架构
    • 3.业务功能模块(例子)
      • 3.1管理员登录接口层(Controller)
      • 3.2管理员登录实现层(ServiceImpl)
      • 3.3管理员登录服务层(Service)
      • 3.4管理员登录Mapper层
    • 4.公共模块
      • 4.1 BaseContext(保存获取登录用户id)
      • 4.2CustomException
      • 4.3GlobalExceptionHandler(全局异常)
      • 4.4对象映射器
      • 4.5公共字段填充
      • 4.6封装返回结果类
    • 5插件模块
      • 5.1Redis序列化器
      • 5.2Web MVC
  • Riji涉及的基础知识
    • DTO
    • 启动类
    • 注解开发
    • @Slf4j
    • @RestController
    • 各个请求路径之间的区别(**http的get、post、put、delete**)
    • @Autowired
    • MP操作中的条件构造器
    • MD5加密
    • 传参的接收不同情况
    • Spring引入的两个基本概念
    • SpringBoot + MP中涉及的分页操作
    • Session的基本用法和知识
    • @Service & @Mapper
    • @Transactional
    • ThreadLocal基本概念和使用
    • 自定义业务异常
    • 全局异常
    • 对象序列化
    • MP中的公共填充
    • 封装结果类
    • 序列化和反序列化 以及 Redis的相关操作
    • webMVC配置

瑞吉外卖

项目位置:https://gitee.com/xue-junbao/reji.git

1.技术栈

  1. 前端

HTML5+CSS+JS+node.js

  1. 后端

JavaSpring Boot + Mybaits Plus + Swagger

  1. 项目

**数据库:**MYSQL,Redis

**部署:**阿里云ECS服务器

2.项目文件架构

如图:

请添加图片描述

多看,基本项目就这几个层级

引入知识:

  1. DTO
  2. 启动类注解

3.业务功能模块(例子)

3.1管理员登录接口层(Controller)

package com.itheima.reggie.controller;//依赖引入
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.reggie.common.R;
import com.itheima.reggie.entity.Employee;
import com.itheima.reggie.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;import static org.apache.commons.lang.StringUtils.isNotEmpty;
import static org.springframework.util.StringUtils.*;@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {@Autowiredprivate EmployeeService employeeService;/*** 员工登录* @param request* @param employee* @return*/@PostMapping("/login")public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee) {/*** 1.对页面提交密码进行md5加密处理* 2.根据用户名查询数据库* 3.如果没有返回失败结果* 4.比对密码* 5.产看员工状态* 6.登录成功,将员工id存入Session并返回登录成功结果*///1String password = employee.getPassword();password = DigestUtils.md5DigestAsHex(password.getBytes());//2LambdaQueryWrapper<Employee> employeeLambdaQueryWrapper = new LambdaQueryWrapper<>();employeeLambdaQueryWrapper.eq(Employee::getUsername,employee.getUsername());Employee emp=employeeService.getOne(employeeLambdaQueryWrapper);//3if(emp == null){return R.error("登录失败");}//4if(!emp.getPassword().equals(password)){return R.error("登录失败");}//5if(emp.getStatus()==0){return R.error("账号禁用!");}//6request.getSession().setAttribute("employee",emp.getId());return R.success(emp);}/*** 员工退出* @param request* @return*/@PostMapping("/logout")public R<String> logout(HttpServletRequest request){//清理Session中保存的当前登录员工的idrequest.getSession().removeAttribute("employee");return R.success("退出成功");}/*** 新增员工* @param employee* @return*/@PostMappingpublic R<String> save(HttpServletRequest request,@RequestBody Employee employee){log.info("新增员工,员工信息:{}",employee.toString());//设置初始密码123456,md5加密处理employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));//        employee.setCreateTime(LocalDateTime.now());
//        employee.setUpdateTime(LocalDateTime.now());
//
//        //获得当前用户登录id
//        Long empID=(Long)request.getSession().getAttribute("employee");
//
//        employee.setCreateUser(empID);
//        employee.setUpdateUser(empID);employeeService.save(employee);return R.success("新增员工成功");}/*** 分页查询*/@GetMapping("/page")public R<Page> page(int page,int pageSize,String name){log.info("page={},pageSize={},name={}",page,pageSize,name);//构造分页构造器Page pageInfo=new Page(page,pageSize);//构造条件构造器LambdaQueryWrapper<Employee> queryWrapper=new LambdaQueryWrapper();//添加过滤条件queryWrapper.like(isNotEmpty(name),Employee::getName,name);//添加排序条件queryWrapper.orderByDesc(Employee::getUpdateTime);//执行查询employeeService.page(pageInfo,queryWrapper);return R.success(pageInfo);}/*** 根据id修改员工信息* @param employee* @return*/@PutMappingpublic R<String> update(HttpServletRequest request, @RequestBody Employee employee){log.info(employee.toString());long id=Thread.currentThread().getId();log.info("线程id为:{}",id);employeeService.updateById(employee);return  R.success("员工信息修改成功!");}/*** 根据id查询员工信息* @param id* @return*/@GetMapping("/{id}")public R<Employee> getById(@PathVariable Long id){log.info("根据id查询员工信息--");Employee employee=employeeService.getById(id);if(employee!=null)return  R.success(employee);elsereturn R.error("没有查询到员工信息");}}

引入知识:

  1. 注解开发
  2. @Slf4j
  3. @RestController
  4. @Autowired
  5. 各个请求Mapper路径之间的区别
  6. MP操作中的条件构造器
  7. MD5加密
  8. 传参的接收不同情况
  9. Spring的两大基础概念
  10. SpringBoot + MP中涉及的分页操作
  11. Session的基本用法和知识

3.2管理员登录实现层(ServiceImpl)

package com.itheima.reggie.service.impl;/*** 实现类*/import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.entity.Employee;
import com.itheima.reggie.mapper.EmployeeMapper;
import com.itheima.reggie.service.EmployeeService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
@Transactional
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
}

引入知识:

  1. @Service注解
  2. @Transactional

3.3管理员登录服务层(Service)

package com.itheima.reggie.service;
/*** 接口*/import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.reggie.entity.Employee;public interface EmployeeService extends IService<Employee> {
}

3.4管理员登录Mapper层

package com.itheima.reggie.mapper;/****/import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.reggie.entity.Employee;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {}

4.公共模块

4.1 BaseContext(保存获取登录用户id)

package com.itheima.reggie.common;/*** @Title: BaseContext* @Author xjb* @Package com.itheima.reggie.common* @Date 2023/11/22 17:09* @description: 基于ThreadLocal封装工具类,用户保存和获取当前登录用户id*/
public class BaseContext {private static ThreadLocal<Long> threadLocal =new ThreadLocal<>();/*** 设置值* @param id*/public static void setCurrentId(Long id){threadLocal.set(id);}/*** 获取值* @return*/public static Long getCurrentId(){return threadLocal.get();}
}

引入知识:

  1. ThreadLocal基本概念和使用

4.2CustomException

package com.itheima.reggie.common;/*** @Title: CustomException* @Author xjb* @Package com.itheima.reggie.common* @Date 2023/11/30 16:16* @description: 自定义业务异常*/
public class CustomException extends RuntimeException{public CustomException(String message){super(message);}
}

引入知识:

  1. 自定义业务异常

4.3GlobalExceptionHandler(全局异常)

package com.itheima.reggie.common;import com.sun.org.glassfish.external.statistics.annotations.Reset;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;import java.sql.SQLIntegrityConstraintViolationException;/*** 全局异常捕获*/
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {/*** 异常处理方法* @param ex* @return*/@ExceptionHandler(SQLIntegrityConstraintViolationException.class)public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){log.error(ex.getMessage());if(ex.getMessage().contains("Duplicate entry")){String[] split = ex.getMessage().split(" ");String msg=split[2]+"已存在";return R.error(msg);}return R.error("未知错误");}/*** 异常处理方法(删除分类)* @param ex* @return*/@ExceptionHandler(CustomException.class)public R<String> exceptionHandler(CustomException ex){log.error(ex.getMessage());return R.error(ex.getMessage());}
}

引入知识:

  1. 全局异常的声明和定义

4.4对象映射器

package com.itheima.reggie.common;import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;/*** 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]*/public class JacksonObjectMapper extends ObjectMapper {public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";public JacksonObjectMapper() {super();//收到未知属性时不报异常this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);//反序列化时,属性不存在的兼容处理this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);SimpleModule simpleModule = new SimpleModule().addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))).addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))).addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))).addSerializer(BigInteger.class, ToStringSerializer.instance).addSerializer(Long.class, ToStringSerializer.instance).addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))).addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))).addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));//注册功能模块 例如,可以添加自定义序列化器和反序列化器this.registerModule(simpleModule);}
}

引入知识:

  1. 对象序列化和反序列化

4.5公共字段填充

package com.itheima.reggie.common;import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;/*** @Title: MyMetaObjecthandler* @Author xjb* @Package com.itheima.reggie.common* @Date 2023/11/22 16:07* @description: 公共字段填充*/
@Slf4j
@Component
public class MyMetaObjecthandler implements MetaObjectHandler {//原数据对象处理器/*** 插入自动填充* @param metaObject*/@Overridepublic void insertFill(MetaObject metaObject){log.info("公共字段自动填充[insert]...");log.info(metaObject.toString());metaObject.setValue("createTime", LocalDateTime.now());metaObject.setValue("updateTime", LocalDateTime.now());metaObject.setValue("createUser", BaseContext.getCurrentId());metaObject.setValue("updateUser", BaseContext.getCurrentId());}/*** 更新自动填充* @param metaObject*/@Overridepublic void updateFill(MetaObject metaObject){log.info("公共字段自动填充[update]...");log.info(metaObject.toString());long id=Thread.currentThread().getId();log.info("线程id为:{}",id);metaObject.setValue("createTime", LocalDateTime.now());metaObject.setValue("updateTime", LocalDateTime.now());metaObject.setValue("updateUser", BaseContext.getCurrentId());}
}

引入知识:

  1. MP中的公共填充

4.6封装返回结果类

package com.itheima.reggie.common;import lombok.Data;
import java.util.HashMap;
import java.util.Map;/*** 通用返回结果类,服务器响应的数据最终都会封装成为此对象* @param <T>*/
@Data
public class R<T> {private Integer code; //编码:1成功,0和其它数字为失败private String msg; //错误信息private T data; //数据private Map map = new HashMap(); //动态数据public static <T> R<T> success(T object) {R<T> r = new R<T>();r.data = object;r.code = 1;return r;}public static <T> R<T> error(String msg) {R r = new R();r.msg = msg;r.code = 0;return r;}public R<T> add(String key, Object value) {this.map.put(key, value);return this;}
}

引入知识:

  1. 封装结果类

5插件模块

5.1Redis序列化器

package com.itheima.reggie.config;import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig extends CachingConfigurerSupport {@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();//默认的Key序列化器为:JdkSerializationRedisSerializerredisTemplate.setKeySerializer(new StringRedisSerializer()); // key序列化//redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); // value序列化redisTemplate.setConnectionFactory(connectionFactory);return redisTemplate;}
}

引入知识:

  1. 序列化和反序列化的意义
  2. Redis的序列化和反序列化

5.2Web MVC

package com.itheima.reggie.config;import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import com.itheima.reggie.common.JacksonObjectMapper;
import com.itheima.reggie.entity.Employee;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;@Slf4j
@Configuration
@EnableSwagger2
@EnableKnife4j
public class WebMvcConfig extends WebMvcConfigurationSupport {/*** 设置静态资源映射* @param registry*/@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {log.info("开始进行静态资源映射...");registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");}/*** 扩展mvc框架的消息转换器* @param converters*/@Overrideprotected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {log.info("扩展消息转换器...");//创建消息转换器对象MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();//设置对象转换器,底层使用Jackson将Java对象转为jsonmessageConverter.setObjectMapper(new JacksonObjectMapper());//将上面的消息转换器对象追加到mvc框架的转换器集合中converters.add(0,messageConverter);}//扫描controller,生成接口文档@Beanpublic Docket createRestApi() {// 文档类型return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage("com.itheima.reggie.controller")).paths(PathSelectors.any()).build();}//描述接口文档private ApiInfo apiInfo() {return new ApiInfoBuilder().title("瑞吉外卖").version("1.0").description("瑞吉外卖接口文档").build();}
}

引入知识:

  1. webMVC配置

Riji涉及的基础知识

DTO

要理解DTO和VO这两个概念就行

  1. DTO可以理解为前端传入的数据过多,一个表塞不下,那么可以对这个表进行扩展然后做为DTO来传输数据
  2. VO则是反着的,后端返回前端数据多要整合成一个VO对象返回

DTO与VO-CSDN博客

启动类

知道注解意思就行

使用Spring Boot构建RESTful服务:项目启动类(瑞吉外卖)-CSDN博客

注解开发

  1. 什么是注解?

Annotion(注解)是一个接口,程序可以通过反射来获取指定程序元素的Annotion对象,然后通过Annotion对象来获取注解里面的元数据。

我们常常使用的注解,@Data、@Controller等等,这些都是注解,创建一个注解,也很简单,创建一个类,然后将class改为 @interface就是一个注解啦。

官方解释:

Java 注解(Annotation)用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java 注解是从 Java5 开始添加到 Java 的。–官方文档

  1. 关于注解的处理

我们一般将利用反射来处理注解的方式称之为运行时注解

另外一种则是编译时注解,如我们常常使用的 lombok 里的注解,@Data,它能够帮我们省略set/get方法,我们在Class上加上这个注解后,在编译的时候,lombok其实是修改了.class文件的,将set/get方法放进去了,不然的话,你可以看看编译完后的.class文件。诸如这种,我们常称为编译时注解,也就是使用javac处理注解。

  1. 注解和反射

**反射定义:**反射(Reflection),Java 中的反射机制是指,Java 程序在运行期间可以获取到一个对象的全部信息。

反射机制一般用来解决Java 程序运行期间,对某个实例对象一无所知的情况下,如何调用该对象内部的方法问题。

二者之间的关系:

  • 互补:注解和反射不是相互替代的,而是可以一起使用的互补机制。注解通常用于添加元数据,而反射则用于在运行时处理这些元数据。
  • 用途:注解通常用于标记代码中的特定部分,以便在编译时或运行时进行处理。反射则用于在运行时动态地检查和操作类、方法和字段。
  • 结合使用:有时,你可以使用注解来存储有关类、方法和字段的信息,然后使用反射来读取和处理这些信息。例如,某些框架(如Spring)使用注解来配置组件,然后在运行时使用反射来识别和初始化这些组件。

**简单理解:**注解可以将一部分配置类操作封装到一个注解接口中,其中可以提供配置类也可以提供一些规则

Java注解详解和自定义注解实战,用代码讲解 - 掘金 (juejin.cn)

@Slf4j

这是一个日志注解,只需要知道怎么用就行

  1. 项目引用:
        <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.10</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId:<version>1.7.28</version></dependency>
  1. 使用

Slf4j日志级别,级别由低到高,设置的级别越低,打印的日志越多
①trace: 一般不会使用,在日志里边也不会打印出来,最低的一个日志级别。
debug: 一般放于程序的某个关键点的地方,用于打印一个变量值或者一个方法返回的信息之类的信息。
info: 一般处理业务逻辑的时候使用,就跟 system.err打印一样,用于说明此处是干什么的。
warn:警告,不会影响程序的运行,但是值得注意。
error:
用户程序报错,必须解决的时候使用此级别打印日志。

@RestController

  1. @RestController是一个组合注解,它包含了@Controller和@ResponseBody两个注解的功能。

用@RestController标记的类表示这是一个RESTful风格的控制器,它可以处理HTTP请求并返回JSON格式的响应。 @RestController注解在处理请求时,会自动将方法的返回值转换为JSON格式的响应体,并返回给客户端。

因此,使用@RestController可以省去在每个方法上都加@ResponseBody注解的麻烦。

@RestController也支持@RequestMapping注解,用于映射请求。

例如,可以在@RestController中定义一个处理GET请求的方法,并使用@RequestMapping注解指定请求的URL和请求方法,如下所示:

@RestController
@RequestMapping("/user")
public class UserController {@GetMapping("/{id}")public User getUserById(@PathVariable Long id) {// 根据id查询用户信息User user = userService.getUserById(id);return user;}
}

上述代码中,@GetMapping注解表示该方法处理GET请求,{@code /{id}}表示URL中的参数,@PathVariable注解用于获取参数值。方法的返回值会自动转换为JSON格式的响应体,返回给客户端。 需要注意的是,使用@RestController时需要确保Spring的Jackson或Gson库已经正确配置,否则无法将Java对象转换为JSON格式的响应

  1. 关于RESTful风格

RESTful风格是一种基于HTTP协议设计Web API的软件架构风格,由Roy Fielding在2000年提出。它强调使用HTTP动词来表示对资源的操作(GET、POST、PUT、PATCH、DELETE等),并通过URI表示资源的唯一标识符。

需要知道:

  1. 在实际应用中,RESTful风格的Web服务通常使用JSON或XML格式进行数据交换。相比于其他Web服务交互方案(如SOAP),RESTful风格更加轻量级和简单明了,因此得到了广泛的应用和支持.

@RestController详解 - 知乎 (zhihu.com)

各个请求路径之间的区别(http的get、post、put、delete)

只需要记住 post用于向服务器提交数据,get拉取数据,put更新数据,delete删除数据就可以了

Spring Boot中的RESTful API:@GetMapping, @PostMapping, @PutMapping, 和 @DeleteMapping详解-CSDN博客

@Autowired

@Autowired 注解能够自动装配 Spring 容器中的 bean,使得开发者无需手动通过 new 关键字或者通过 getBean() 方法来获取依赖对象。

简单说就是自动创建和配置对应type的对象,有点像工厂模式。

深入解析 Spring 的 @Autowired:自动装配的魔法与细节-CSDN博客

MP操作中的条件构造器

关于项目中的操作我们可以将步骤分为:

  1. 构造条件构造器
  2. 确定条件并且构造条件
  3. 封装条件构造器并查询
  4. 封装结果执行下一步操作

员工登录为例

        //1构造条件选择器LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();//2构造条件并且封装queryWrapper.eq(Employee::getUsername,employee.getUsername());//3开始查询数据,获取返回结果Employee emp = employeeService.getOne(queryWrapper);//4比对数据,看是否可以登录if(emp == null){return R.error("登录失败");}if(!emp.getPassword().equals(password)){return R.error("登录失败");}if(emp.getStatus()==0){return R.error("账号禁用!");}request.getSession().setAttribute("employee",emp.getId());

基础操作看链接:

MyBatis-Plus 基础:LambdaQueryWrapper详解与实例-CSDN博客

MD5加密

只需要学会直接调用Spring提供的DigestUtils.md5DigestAsHex方法完成md5加密操作就可以了。

此项目管理员登录中:

//管理员登录
String password = employdee.getPassword();password = DigestUtils.md5DigestAsHex(password.getBytes());//登录获取的密码通过加密和sql中的数据进行比对//增加用户//设置初始密码123456,md5加密处理employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));

Java中的MD5加密详解-CSDN博客

传参的接收不同情况

搞清楚各个注解处理的数据类型:

重点有@RequestBody处理的是JSON和XML类型的数据,@PathVariable处理的是URL上绑定的参数,无注解时会自己寻找一个匹配的参数(要求名字对应)

Spring MVC注解详解与实战:从请求处理到数据绑定-CSDN博客

Spring引入的两个基本概念

简单了解一下就好了。

  1. IOC控制反转,就是将类写成bean类让获取的时候无需关注创建和配置的过程

  2. AOP切面编程,就是对程序进行横向切分,添加额外的行为或功能。AOP常用于实现日志记录、事务管理、安全检查等横切关注点,项目中涉及的公共字段填充就是用的AOP。可以理解为一个配置一次全局自动触发的工具。

控制反转(IoC)与面向切面编程(AOP)-CSDN博客

SpringBoot + MP中涉及的分页操作

项目中的使用:

  1. 构造分页器
  2. 构造查询条件
  3. 执行分页查询

例如:

//构造分页器
Page pageInfo = new Page(page,pageSize);//构造条件构造器
LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper();
//添加过滤条件
wrapper.like(isNotEmpty(name),Employee::getName,name);//第一个参数是执行的条件 
//添加排序条件wrapper.orderByDesc(Employee::getUpdateTime);//降序排列//执行查询
employeeService.page(pageInfo,wrapper);return pageInfo;

SpringBoot + MyBatis-Plus 实现分页操作详解-CSDN博客

Session的基本用法和知识

项目中只需要会最基本的如何获取session,设置以及应用场景。

本项目中,例如:

        request.getSession().setAttribute("employee",emp.getId());

就是设置一个session,存入了当前用户的权限信息和id

不要忘了传入的参数为public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee)里面应该有HttpServletRequest request

获取和删除session为:request.getSession().getAttribute("employee")request.getSession().removeAttribute("employee");

Java中的Session详解及示例代码-CSDN博客

@Service & @Mapper

简单理解,这个注解使得

当类上标注了@Service注解后,Spring容器会自动扫描并创建该类的一个实例(即Bean),这样我们就可以在其他地方通过自动装配(Autowired)的方式注入这个Bean。

Spring Boot实战:深入理解@Service与@Mapper注解-CSDN博客

@Transactional

这个注解可以保证在操作多个数据库表单时候,确保事物的一致性,也就是说,只有所有的操作都成功才会成功,否则就会回滚让所有操作都失败。

ThreadLocal基本概念和使用

简答说就是保存一个数据,方便同一线程内的其它地方调用数据,降低复杂程度

ThreadLocal和简单应用-CSDN博客

自定义业务异常

学会如何使用可以让项目更加规范!!!

Java中的自定义异常处理:业务异常类的创建与使用-CSDN博客

全局异常

统一管理全局异常抛出

深入理解Java Spring中的全局异常处理:以Reggie项目为例-CSDN博客

对象序列化

了解其原理和应用,这种代码都是写死的,不用记。

JacksonObjectMapper自定义配置详解-CSDN博客

MP中的公共填充

学明白,后续会有Mabatis的操作,同时应用AOP。

MyBatis-Plus中的公共字段自动填充策略-CSDN博客

封装结果类

Java通用返回结果类的设计与应用-CSDN博客

序列化和反序列化 以及 Redis的相关操作

  1. 序列化和反序列化详解-CSDN博客
  2. 自定义Redis配置以优化你的Spring应用-CSDN博客

webMVC配置

项目最基础的配置,需要指定资源路径和API文档

Spring Boot中WebMvcConfig配置详解及示例-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/229260.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

王力机器人安全门|用细节开拓高端精致家居生活

细微之处见风范,毫厘之优定乾坤。在追求高端品质的道路上,细节往往是最有力的诠释。如在入户门的选择方面,考虑到老人、孩子、宠物等每一位家庭成员不同需求的设计、科技运用才称得上是充满人性化、品质化的高端细节,幸福感直抵心灵。在该方面,王力机器人安全门做出了表率,每一…

【连接池】-从源码到适配(下),使用dynamic-datasource导致连接池没生效(升级版本)

写在前面 书接上文&#xff0c;连接池没生效&#xff0c;启用了一个什么默认的连接池。具体是什么&#xff0c;一起来看看源码吧。 目录 写在前面一、问题描述二、本地调试三、升级dynamic-datasource四、新的问题&#xff08;一&#xff09;数据源初始化问题&#xff08;二&am…

公司创建百度百科需要哪些内容?

一个公司或是一个品牌想要让自己更有身份&#xff0c;更有知名度&#xff0c;更有含金量&#xff0c;百度百科词条是必不可少的。通过百度百科展示公司的详细信息&#xff0c;有助于增强用户对公司的信任感&#xff0c;提高企业形象。通过百度百科展示公司的发展历程、领导团队…

ASP.Net实现汽车添加查询(三层架构,含照片)

演示功能&#xff1a; 点击启动生成页面 点击搜索模糊查询 点击添加跳转新界面 此处设置文本框多行 点击Button添加 步骤&#xff1a; 1、建文件 下图是三层架构列表&#xff0c;Models里面有模拟数据库中列的类&#xff0c;DAL中有DBHelper和service,BLL中有BllManager文件…

TiDB 7.5 LTS 发版丨提升规模化场景下关键应用的稳定性和成本的灵活性

互联网时代&#xff0c;数据的迅猛增长给数据库带来了可扩展性的挑战&#xff0c;Gen AI 带来的数据暴增更加剧了这种挑战。传统的数据分片已经不能承载新时代数据暴增的需求&#xff0c;更简单且具有前瞻性的方法则是采用原生分布式数据库来解决扩展性问题。在这种规模化场景的…

SpringValidation自定义注解以及分组校验

SpringValidation的参数校验使用可参考&#xff1a;【SpringMVC应用篇】Spring Validation 参数校验-CSDN博客 目录 1. 引入依赖 2. 自定义注解校验 2.1 创建Validation类 2.2 创建注解对象 2.3 使用注解 3. 分组校验 3.1 实体类内部定义接口 3.2 在参数上指定分组 1. …

CISSP 第1章:实现安全治理的原则和策略

作者&#xff1a;nothinghappend 链接&#xff1a;https://zhuanlan.zhihu.com/p/669881930 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 CIA CIA 三性&#xff1a; 机密性&#xff1a;和数据泄露有关。完整性…

存算分离降本增效,StarRocks 助力聚水潭 SaaS 业务服务化升级

作者&#xff1a;聚水潭数据研发负责人 溪竹 聚水潭是中国领先的 SaaS 软件服务商&#xff0c;核心产品是电商 ERP&#xff0c;协同350余家电商平台&#xff0c;为商家提供综合的信息化、数字化解决方案。公司是偏线下商家侧的 toB 服务商&#xff0c;员工人数超过3500&#xf…

C++初阶------------------入门C++

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

带大家做一个,易上手的家常糖醋白菜

准备 如果是大白菜就一个 小白菜就要两个 因为白菜炒完之后会变少 将白菜叶剥开每叶分成三个小块 整个剥完之后 放入盆中清洗干净 调一个糖醋汁 一勺料酒 两勺生抽 三勺白砂糖 四勺香醋 起锅烧油 放两个干辣椒 辣椒炒一下 然后倒入白菜 翻炒直到油全部融入白菜 然后倒入…

Windows本地如何部署Apache服务器搭配内网穿透实现无公网IP远程访问?

文章目录 前言1.Apache服务安装配置1.1 进入官网下载安装包1.2 Apache服务配置 2.安装cpolar内网穿透2.1 注册cpolar账号2.2 下载cpolar客户端 3. 获取远程桌面公网地址3.1 登录cpolar web ui管理界面3.2 创建公网地址 4. 固定公网地址 前言 Apache作为全球使用较高的Web服务器…

自然语言处理1——探索自然语言处理的基础 - Python入门篇

目录 写在开头1. 介绍自然语言处理的基本概念1.1 NLP的核心目标1.2 常见的NLP任务1.3 应用场景详细介绍1.3.1 医疗保健1.3.2 金融领域1.3.3 教育领域1.3.4 社交媒体分析 2. Python中常用的自然语言处理库简介2.1 NLTK (Natural Language Toolkit)2.2 Spacy2.3 Transformers2.4 …

张量操作与线性回归

一、张量的操作&#xff1a;拼接、切分、索引和变换 &#xff08;1&#xff09;张量拼接与切分 1.1 torch.cat() 功能&#xff1a;将张量按维度dim进行拼接 • tensors: 张量序列 • dim : 要拼接的维度 torch.cat(tensors, dim0, outNone)函数用于沿着指定维度dim将多个张量…

ES6之生成器(Generator)

✨ 专栏介绍 在现代Web开发中&#xff0c;JavaScript已经成为了不可或缺的一部分。它不仅可以为网页增加交互性和动态性&#xff0c;还可以在后端开发中使用Node.js构建高效的服务器端应用程序。作为一种灵活且易学的脚本语言&#xff0c;JavaScript具有广泛的应用场景&#x…

复兴计划01-lc06

StringBuilder和StringBuffer的区别 1. StringBuffer和StringBuilder都是用于字符串动态拼接,但是StringBuffer拼接的函数方法的实现中用了synchornized上锁&#xff0c;效率较低&#xff0c;不过可以用于多线程以此来维护线程安全&#xff1b;相比之下&#xff0c;StringBuil…

理解SQL中not in 与null值的真实含义

A not in B的原理是拿A表值与B表值做是否不等的比较, 也就是a ! b. 在sql中, null是缺失未知值而不是空值。 当你判断任意值a ! null时, 官方说, “You cannot use arithmetic comparison operators such as , <, or <> to test for NULL”, 任何与null值的对比都将返…

Postman使用

Postman使用 Pre-request Script 参考&#xff1a; Scripting in Postman 可以请求、集合或文件夹中添加Pre-request Script&#xff0c;在请求运行之前执行JavaScript 如设置变量值、参数、Header和正文数据&#xff0c;也可以使用Pre-request Script来调试代码&#xff0…

jupyter notebook打开其他盘的文件

jupyter notebook打开其他盘文件 打开jupyter notebook打开terminal输入&#xff1a;jupyter-notebook 路径打开你想打开的工程的文件 打开jupyter notebook 打开terminal 输入&#xff1a;jupyter-notebook 路径 打开你想打开的工程的文件

TDD-LTE 寻呼流程

目录 1. 寻呼成功流程 1.1 空闲态寻呼 1.2 连接态寻呼 2. 寻呼失败流程 2.1 Paging消息不可达 2.2 RRC建立失败 2.3 eNodeB未上发Initial UE message或达到超时 1. 寻呼成功流程 1.1 空闲态寻呼 寻呼成功&#xff1a;MME发起寻呼&#xff08;S1 接口发送Paing 消息&…

【docker实战】安装tomcat并连接mysql数据库

本节用docker来安装tomcat&#xff0c;并用这个tomcat连接我们上一节安装好的mysql数据库 一、拉取镜像 我们安装8.5.69版本 先搜索一下 [rootlocalhost ~]# docker search tomcat NAME DESCRIPTION …