当前位置: 首页 > news >正文

瑞吉外卖项目详细总结

文章目录

  • 瑞吉外卖
    • 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博客

相关文章:

瑞吉外卖项目详细总结

文章目录 瑞吉外卖1.技术栈2.项目文件架构3.业务功能模块&#xff08;例子&#xff09;3.1管理员登录接口层(Controller)3.2管理员登录实现层(ServiceImpl)3.3管理员登录服务层&#xff08;Service&#xff09;3.4管理员登录Mapper层 4.公共模块4.1 BaseContext&#xff08;保存…...

Cytoscape 3.10安装包下载及安装教程

Cytoscape3.10下载链接&#xff1a;https://docs.qq.com/doc/DUkpuR0RVU0JVWkFP 1、选中下载好的安装包&#xff0c;右键选择解压到“Cytoscape 3.10”文件夹 2、双击打开“Cytoscape_3_10_0_windows_64bit.exe” 3.点击“Download”&#xff0c;请耐心等待“Java”完成 4、点击…...

data.TensorDataset解析

data.TensorDataset 是 PyTorch 中的一个类&#xff0c;用于创建一个包含多个张量的数据集。这个类的主要作用是将输入的张量组合成一个数据集&#xff0c;使得在训练过程中可以方便地进行数据加载和迭代。 具体来说&#xff0c;TensorDataset 接受一系列的张量作为输入参数&a…...

贝锐花生壳全新功能:浏览器一键远程访问SSHRDP远程桌面

为了满足特定场景的远程访问需求&#xff0c;如&#xff1a;远程群晖NAS设备、远程SQL Server数据库/MySQL数据库、3389远程桌面&#xff08;RDP远程桌面&#xff09;、远程SSH、我的世界游戏联机…… 贝锐花生壳推出了场景映射服务&#xff0c;不仅提供满足相应场景的网络带宽…...

2024 年度 AAAI Fellows 揭晓!清华大学朱军教授入选!

今日&#xff0c;国际人工智能领域最权威的学术组织 AAAI 揭晓 2024 年度 Fellows 评选结果&#xff0c;新增 12 位 Fellow。 其中&#xff0c;清华大学计算机系教授朱军因「在机器学习理论与实践方面做出的重大贡献」而成功入选&#xff0c;成为本年度入选的唯一华人学者&…...

Linux(openssl):用CA证书签名具有SAN的CSR

Linux(openssl):创建CA证书,并用其对CSR进行签名_生成ca证书签名请求文件csr-CSDN博客 提供了方法为CSR进行签名。 对于有SAN的CSR如何签名呢? 1.创建CA证书,与下面的帖子一样...

从零开始了解大数据(七):总结

系列文章目录 从零开始了解大数据(一)&#xff1a;数据分析入门篇-CSDN博客 从零开始了解大数据(二)&#xff1a;Hadoop篇-CSDN博客 从零开始了解大数据(三)&#xff1a;HDFS分布式文件系统篇-CSDN博客 从零开始了解大数据(四)&#xff1a;MapReduce篇-CSDN博客 从零开始了解大…...

增量预训练经验积累(3)

站在巨人的肩膀上才能走的更远~本文主要是针对《千亿参数开源大模型 BLOOM 背后的技术》进行学习和提取关键经验。 1、BLOOM与Megatron-DeepSpeed 1.1 BLOOM训练细节 BLOOM 的模型架构与 GPT3 非常相似,只是增加了一些改进,176B BLOOM 模型的训练于 2022 年 3 月至 7 月期…...

R语言【CoordinateCleaner】——cc_dupl():根据物种名称和坐标以及用户定义的附加列删除或标记重复的记录

Package CoordinateCleaner version 2.0-20 Parameters cc_dupl(x,lon "decimallongitude",lat "decimallatitude",species "species",additions NULL,value "clean",verbose TRUE ) 参数【x】&#xff1a;data.frame。包含地…...

Hadoop安装笔记1单机/伪分布式配置_Hadoop3.1.3——备赛笔记——2024全国职业院校技能大赛“大数据应用开发”赛项——任务2:离线数据处理

将下发的ds_db01.sql数据库文件放置mysql中 12、编写Scala代码&#xff0c;使用Spark将MySQL的ds_db01库中表user_info的全量数据抽取到Hive的ods库中表user_info。字段名称、类型不变&#xff0c;同时添加静态分区&#xff0c;分区字段为etl_date&#xff0c;类型为String&am…...

python数据分析之交叉验证

python数据分析之交叉验证 1、常用的分类算法 有监督:SVM向量机、梯度提升、决策树(随机森林)、朴素贝叶斯、逻辑斯蒂回归、神经网络(cnn、rnn) 无监督:k-means、隐马尔可夫 2、数据分析过程 1、采集数据 2、数据预处理 3、特征选择 4、模型训练、评估、保存 5、模型…...

机器人技能学习--数据集剖析

文章目录 前言数据总览数据介绍actionsrobot0_eef_poserobot0_eef_quatstatesobject 参考资料 前言 一切为了能自己构建属于自己的数据集&#xff0c;所以&#xff0c;从现有数据集剖析入手。    目前&#xff0c;基于 MimicGen 官方提供的数据集&#xff0c;初始数据集有11组…...

Jenkins的Transfers路径怎么配置,解决Transfers配置不生效的问题

Transfers配置: 1.配置Source files: 要填写jar包的相对路径,从当前项目工作空间的根目录开始,看看我的工作空间你就懂了 !如图 我填的是 parent/build/libs/parent-1.0.0.jar,即不要 fdw1/ 的前缀 2.配置Remote directory: 远程目标文件夹,也就是你jar包要放到远程…...

php安装扩展event 提示 No package ‘openssl‘ found 解决方法

在使用pecl编译安装最新版event模块的时候提示 No package openssl found , 可是本机是安装了openssl的, 编译时找不到, 大概率就是环境配置的问题了, 增加 OPENSSL_CFLAGS OPENSSL_LIBS环境变量即可解决. 异常提示信息: checking for openssl > 1.0.2... no configure: …...

基于SpringBoot的动物领养平台的设计与实现

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的动物领养平台的设计与实…...

计算机网络期末复习——计算大题(一)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的在校大学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;V…...

2024年深度学习、计算机视觉与大模型面试题综述,六大专题数百道题目

DeepLearning-Interview-Awesome-2024 本项目涵盖了大模型(LLMs)专题、计算机视觉与感知算法专题、深度学习基础与框架专题、自动驾驶、智慧医疗等行业垂域专题、手撕项目代码专题、优异开源资源推荐专题共计6大专题模块。我们将持续整理汇总最新的面试题并详细解析这些题目&a…...

解读 $mash 通证 “Fair Launch” 规则,将公平发挥极致

Solmash 是 Solana 生态中由社区主导的铭文资产 LaunchPad 平台&#xff0c;该平台旨在为 Solana 原生铭文项目&#xff0c;以及通过其合作伙伴 SoBit 跨链桥桥接到 Solana 的 Bitcoin 生态铭文项目提供更广泛的启动机会。有了 Solmash&#xff0c;将会有更多的 Solana 生态的铭…...

06、docker 安装mysql8

Docker 安装 MySQL8 下载mysql8的镜像 docker pull mysql:8.0.32启动镜像 docker run -p 3307:3306 --name mysql8 -e MYSQL_ROOT_PASSWORD123456 -d mysql:8.0.32配置挂载 创建挂载目录 mkdir -p /docker/mysql8.0.32/copy配置文件到创建的目录下 docker cp mysql:/etc/mysql…...

魔改Stable Diffusion,开源创新“单目深度估计”模型

单目深度估计一直是计算机视觉领域的难点。仅凭一张 RGB 图像,想要还原出场景的三维结构,在几何结构上非常不确定,必须依赖复杂的场景理解能力。 即便使用更强大的深度学习模型来实现&#xff0c;也面临算力需求高、图像数据注释量大、泛化能力弱等缺点。 为了解决这些难题&a…...

使用JAVA Zookeeper构建分布式键值存储

在这篇文章中,我将使用 JAVA 和网络套接字构建一个简单的分布式键值存储。 我将展示如何在具有多个分区和复制的集群中使用 Zookeeper 作为协调服务。 本系统中Zookeeper服务的功能如下: 维护从服务器到分区的映射,即哪些服务器属于分区“i”。这些数据还可用于推断哪些服务…...

2023-12-19 LeetCode每日一题(寻找峰值 II)

2023-12-19每日一题 一、题目编号 1901. 寻找峰值 II二、题目链接 点击跳转到题目位置 三、题目描述 一个 2D 网格中的 峰值 是指那些 严格大于 其相邻格子(上、下、左、右)的元素。 给你一个 从 0 开始编号 的 m x n 矩阵 mat &#xff0c;其中任意两个相邻格子的值都 不…...

gin框架使用系列之五——表单校验

系列目录 《gin框架使用系列之一——快速启动和url分组》《gin框架使用系列之二——uri占位符和占位符变量的获取》《gin框架使用系列之三——获取表单数据》《gin框架使用系列之四——json和protobuf的渲染》 一 、表单验证的基本理论 在第三篇中&#xff0c;我们介绍了如何…...

HackTheBox - Medium - Linux - Interface

Interface Interface 是一种中等难度的 Linux 机器&#xff0c;具有“DomPDF”API 端点&#xff0c;该端点通过将“CSS”注入处理后的数据而容易受到远程命令执行的影响。“DomPDF”可以被诱骗在其字体缓存中存储带有“PHP”文件扩展名的恶意字体&#xff0c;然后可以通过从其…...

C++ 字符串操作说明 续

一、strstr函数 extern char *strstr(char *str1, const char *str2); 1. strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是&#xff0c;则该函数返回str2在str1中首次出现的地址&#xff1b;否则&#xff0c;返回NULL。 2. str1: 被查找目标 string …...

[情商-7]:如何回答没有标准答案的两难问题

目录 前言&#xff1a; 一、用“逻辑推理思维”回答两难问题 二、用“情绪思维”回答两难问题 1.1 关注提问者提出问题背后的情绪状态和情绪/情感诉求 1.2 常见的常见的情绪和情感诉求 1.3 女性情感分析 1.4 理解女性情感的语言 1.5 如何通过语言理解女性的情绪需求 三…...

对偶问题的基本性质

写于&#xff1a;2024年1月3日晚 修改于&#xff1a; 原规划与对偶规划 原规划对偶规划 max ⁡ z C T X s.t. { A X ≤ b , 其中 X ( m ∗ 1 ) X ≥ 0 \begin{aligned} & \max \mathrm{z}\mathbf{C}^T \mathbf{X} \\ & \text { s.t. }\left\{\begin{array}{l}\mat…...

Google Chrome 现在会在后台扫描泄露的密码

谷歌表示&#xff0c;Chrome 安全检查功能将在后台运行&#xff0c;检查网络浏览器中保存的密码是否已被泄露。 如果桌面用户正在使用标记为危险的扩展程序&#xff08;从 Chrome Web Store 中删除&#xff09;、最新的 Chrome 版本&#xff0c;或者如果启用安全浏览来阻止 Go…...

【Matlab】PSO-BP 基于粒子群算法优化BP神经网络的数据时序预测(附代码)

资源下载&#xff1a; https://download.csdn.net/download/vvoennvv/88689096 目录 【Matlab】BP 神经网络时序预测算法 【Matlab】CNN卷积神经网络时序预测算法 【Matlab】ELM极限学习机时序预测算法 【Matlab】基于遗传算法优化BP神经网络 (GA-BP)的数据时序预测 【Mat…...

Linux 485驱动通信异常

背景 前段时间接到一个项目&#xff0c;要求用主控用485和MCU通信。将代码调试好之后&#xff0c;验证没问题就发给测试了。测试测的也没问题。 但是&#xff0c;到设备量产时&#xff0c;发现有几台设备功能异常。将设备拿回来排查&#xff0c;发现是485通信有问题&#xff…...

大连网站建设培训班/新手如何找cps推广渠道

基本了解&#xff1a;mysql数据库为关系型数据库&#xff0c;个关系型数据库由一个或数个表格组成&#xff0c;表格中肯定有键(键(key): 表中用来识别某个特定的人物的方法, 键的值在当前列中具有唯一性。)登录mysql(记得配置环境变量)管理员模式打开cmd启动服务net start mysq…...

如何查看网站点击量/查询网站流量的网址

1.触发器 这是一个非常简单直接的解决方案&#xff0c;我们只需要将DTS引擎驻留在比如windows服务中&#xff0c;该引擎通过数据库的触发器事件获取源表数据更新的所有情况&#xff0c;即增量&#xff0c;然后相应的更新目的表。然而&#xff0c;由谁来创建触发器了&#xf…...

wordpress评论验证码插件/免费网站申请域名

...

广州越秀番禺最新通告/浙江seo推广

一、用户输入验证1、手工编程验证动作类中的所有方法进行验证&#xff1a;步骤&#xff1a;a、动作类继承ActionSupportb、覆盖调用public void validate()方法c、在validate方法中&#xff0c;编写不符合要求的代码判断&#xff0c;并调用父类的addFieldError(String fieldNam…...

美食网站代做/软文推广多少钱一篇

1. 修改类函数。 场景&#xff1a; 如果要给一个类的所有方法加上计时&#xff0c;并打印出来。demo如下&#xff1a; # -*- coding:utf-8 -*- import time def time_it(fn):"Example of a method decorator"def decorator(*args, **kwargs):t1time.time()ret fn(*a…...

彩票网站定制/站长之家seo一点询

文章目录ContributionAssumptionProperties of the Model首先来定义POMDP:接下来引入information vector接下来就是引入α\alphaα-vectorα\alphaα-vector的证明ExamplesAn Algorithm for Computing Vn(π)V_{n}(\pi)Vn​(π)Contribution This paper demonstrates that, if…...