目录
SpringMVC的Controller是单例还是多例,有没有并发安全问题,如何解决?
RequestMapping 和 GetMapping有什么区别?
PreparedStatement和Statement的区别
3. 使用 @ConfigurationProperties 注解:
spring-boot-starter-parent的作用?
SpringMVC是一个基于Java的Web框架,在SpringMVC中,应用程序的逻辑被分解成三个主要部分:
MVC包含了Model模型、View视图、Controller控制层。
1、模型(Model):用于对程序的业务逻辑和数据进行处理,然后传递给视图进行展示。
2、视图(View):用于将数据展示给用户。
3、控制层(Controller):用于接收用户的请求,根据请求的内容调用适当的模型和视图,并将处理结果返回给用户。
MVC 架构程序的工作流程:
(1)用户通过 View 页面向服务端提出请求,可以是表单请求、超链接请求、AJAX 请求等
(2)服务端 Controller 控制器接收到请求后对请求进行解析,找到相应的 Model 对用户请求进行处理。
(3)Model 处理后,将处理结果再交给 Controller。
(4)Controller 在接到处理结果后,根据处理结果传递给 View 页面。页面经渲染(数据填充)后,再发送给客户端。
假设我们要开发一个简单的图书管理系统,使用 Spring MVC 框架。我们将创建一个简单的示例来说明其中的 Model、View 和 Controller。
1.Model(模型): 在这个示例中,模型表示图书的数据。我们可以创建一个 Book
类来表示图书对象,包含图书的标题、作者和出版日期等信息。
- public class Book {
- private String title;
- private String author;
- private LocalDate publicationDate;
-
- // 构造函数、getter 和 setter 等
- }
2.View(视图): 视图负责展示数据给用户。在这个示例中,我们可以创建一个 JSP 视图来显示图书的信息。
- DOCTYPE html>
- <html>
- <head>
- <title>图书详情title>
- head>
- <body>
- <h1>图书详情h1>
- <p>标题:${book.title}p>
- <p>作者:${book.author}p>
- <p>出版日期:${book.publicationDate}p>
- body>
- html>
3.Controller(控制器): 控制器处理用户请求,调用适当的模型和视图,并将结果返回给用户。在这个示例中,我们可以创建一个 Spring MVC 控制器来处理图书详情的请求。
- @Controller
- @RequestMapping("/books")
- public class BookController {
-
- @Autowired
- private BookService bookService;
-
- @GetMapping("/{id}")
- public String getBookDetails(@PathVariable Long id, Model model) {
- Book book = bookService.getBookById(id);
- model.addAttribute("book", book);
- return "bookDetails"; // 返回视图名
- }
- }
在上述例子中,BookController是控制器类,使用@RequestingMapping定义了基础请求路径。getBookDetails方法处理/book/{id}请求,通过BookService 获取图书信息,然后将图书数据添加到模型中,最后返回视图名 "bookDetails"。
综上所述,在这个示例中:
表现层(Presentation Layer):用户界面(一是接收前端ajax请求,二是返回json数据给前端)【Controller】
业务逻辑层(Business Logic Layer):接收前端的请求进行逻辑处理,然后与数据库进行交互。
数据访问层(Data Access Layer):对数据库进行操作(针对数据的增添、删除、修改、查找等),并将获得的数据返回到上一层(也就是业务逻辑层)。
Springmvc框架的执行步骤
第一步:用户发起请求到前端控制器(DispatcherServlet)。第二步:前端控制器请求处理器映射器查找Handler。
第三步:处理器映射器向前端控制器返回Handler。
第四步:前端控制器调用处理器适配器去执行Handler。
第五步:处理器适配器去执行Handler。
第六步: Handler执行完成给适配器返回ModelAndView。第七步:处理器适配器向前端控制器返回ModelAndView(模型和视图),ModelAndView是springmvc框架的一个底层对象,包括Model和View。
第八步:前端控制器请求视图解析器去进行View视图解析,根据逻辑图名解析成真正的视图(jsp)第九步:视图解析器向前端控制器返回View对象。
第十步∶前端控制器进行视图渲染,向用户响应结果。
重定向(Redirect)是指从一个页面跳转到另一个页面,是不同的请求,无法共享request中的数据,地址栏会发生改变。它是客户端行为(客户端进行重定向)。
转发(forward)是指从一个页面跳转到另一个页面,是相同的请求,可以共享request中的数据,地址栏不会发生改变,它是服务器行为(在服务器内部进行转发的)
springmvc默认是使用转发方式跳转的,且会经过视图解析器,我们也可以通过指定跳转方式,转发时在返回值前面加"forward:"关键字,重定向时在返回值前面加"redirect:",且此时就不会再经过视图解析器了
重定向的使用方法:
- @RequestMapping("/redirectToPage")
- public String redirectToPage() {
- return "redirect:/newPage"; // 重定向到 /newPage 路径
- }
转发的使用方法:
- @RequestMapping("/forwardToPage")
- public String forwardToPage() {
- return "forward:/anotherPage"; // 转发到 /anotherPage 路径
- }
第一种需求,后台接收前台页面返回的string类型时间,要转换成的Date类型数据,可以使用@DateTimeFormat注解来接收参数【后端接收前端String类型时间】
第二种需求,后台将Date类型数据返回给前台页面,默认是返回时间戳,如果想要优雅的格式,可以在模型的Date字段或get方法上使用@JsonFormat注解,记住要导入jackson的相关依赖 【前端接收后端传递的时间】
@Controller:用来标识一个类为SpringMVC控制器。
@RequestMapping:用来映射请求路径和参数。
@GetMapping、@PostMapping、@PutMapping、@DeleteMapping: 用于指定特定 HTTP 方法的映射。
@ResponseBody:将方法的返回值转换成json格式返回给调用方。
@RequestBody:接收前端存放在数据包中的请求体中的数据。用对象进行接收。
@PathVariable:从请求路径中获取参数【user?id=1等】,通常用在restful接口中。
@RequestParam:从请求参数中获取参数。
@RestController【复合注解】 = @Controller + @ResponseBody 在Controller层进行使用
@RestControllerAdvice:运用aop的思想,对全局异常做一些处理,比如结合@ExceptionHandler做全局异常捕获。
@Component 及派生注解: 用于标识一个类为 Spring 组件,交由 Spring 容器管理。包括 @Controller、@Service、@Repository 等。
@Autowired: 自动装配,用于将 Spring 容器中匹配的 Bean 自动注入到字段、方法参数、构造函数中。
@Resource:自动装配,通过名字进行注入。
@Qualifier: 结合 @Autowired 使用,指定注入的 Bean 名称,解决多个匹配类型 Bean 的冲突。
@Configuration: 声明一个类为 Spring 配置类,可以在其中定义 Bean。
@Bean: 在配置类中使用,将方法的返回值作为 Bean 注册到 Spring 容器。
@Value: 用于注入属性值,支持从配置文件中读取。
@Transactional: 用于标识事务管理的方法或类,控制事务的提交和回滚。
@Aspect: 声明一个切面,用于实现面向切面编程(AOP)。
@Scheduled: 定时任务注解,用于指定方法定时执行。
SpringMVC 的拦截器主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、登录验证等功能上
第1步,定义拦截器:通过自定义类实现 HandlerInterceptor 接口表明当前类是一个拦截器,并加上注解@component交给Spring容器进行管理,并且需要实现接口中的三个方法,preHandler方法是在请求到达处理器(就是在去访问springmvc后端controller)之前执行,postHandle方法是在请求经过处理器之后、解析试图之前执行,afterCompletion方法是在视图渲染之后(modelAndView)、返回客户端之前执行。
第2步,配置拦截器:在springmvc的配置文件xml中(如 dispatcher-servlet.xml),配置需要拦截的路径,配置需要放行的路径。【白名单的直接不会进入拦截器】
步骤:
1. 创建一个类实现 Spring 的 HandlerInterceptor 接口,该接口包含三个方法:preHandle、postHandle 和 afterCompletion。你可以根据需要实现这些方法来执行相应的操作。
2.在 Spring 的配置文件(如 dispatcher-servlet.xml)中,配置拦截器并指定拦截的路径。
示例:
假设我们要创建一个简单的拦截器来记录请求的处理时间。
1.创建一个拦截器类 ExecutionTimeInterceptor,实现 HandlerInterceptor 接口:
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- import org.springframework.web.servlet.HandlerInterceptor;
- import org.springframework.web.servlet.ModelAndView;
-
- public class ExecutionTimeInterceptor implements HandlerInterceptor {
-
- private long startTime;
-
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception {
- startTime = System.currentTimeMillis();
- return true;
- }
-
- @Override
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
- ModelAndView modelAndView) throws Exception {
- long endTime = System.currentTimeMillis();
- long executionTime = endTime - startTime;
- System.out.println("Request took " + executionTime + " milliseconds");
- }
-
- @Override
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
- throws Exception {
- // This method is called after the request has been completed
- }
- }
2.配置拦截器在 Spring 的配置文件中(如 dispatcher-servlet.xml):
- <mvc:interceptors>
- <mvc:interceptor>
- <mvc:mapping path="/*"/>
- <bean class="com.example.ExecutionTimeInterceptor"/>
- mvc:interceptor>
- mvc:interceptors>
在这个示例中,我们配置了一个拦截器来拦截所有路径,然后在 postHandle 方法中计算请求的执行时间并进行输出。
过滤器Filter:
位置不同:基于Servlet的,在请求到达Servlet前后进行处理,作用于Servlet容器层面。
功能不同:过滤器常用于请求和响应的处理,如字符编码转换,请求参数处理等;
如何实现过滤器:实现Filter接口,重写;dofilter方法,在配置文件中web.xml进行配置过滤器,所有请求都会进行过滤:经过逻辑判断是否是登录请求和用户是否登录,才进行放行。
拦截器interceptor:
位置不同:基于SpringMVC(Controller)的,在请求到达Controller前后进行处理,作用于SpringMVC框架层面。
功能不同:拦截器可常用于进入Controller之前或离开Controller之后执行一些特定的操作,如登录校验,权限验证,日志记录等。
如何实现拦截器:实现HandlerInteceptor接口,重写三个方法prehandle,posthandle,aftercompletion()方法,在配置文件中配置拦截器,定义黑白名单。
注:Servlet主要用于接收客户端(浏览器)发送的请求并生成响应。它运行在服务器端,可以处理各种类型的请求,如HTTP请求。
1.创建一个类,实现 javax.servlet.Filter 接口,并重写 doFilter 方法来实现过滤逻辑。
2.使用 @Component 注解将该类标记为 Spring Bean,以便 Spring Boot 自动扫描并管理它。
3.(可选)在 application.properties 或 application.yml 中配置过滤器的相关属性。
1.创建一个过滤器类 CustomFilter,实现 javax.servlet.Filter 接口:
- import javax.servlet.Filter;
- import javax.servlet.FilterChain;
- import javax.servlet.FilterConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import java.io.IOException;
-
- import org.springframework.stereotype.Component;
-
- @Component
- public class CustomFilter implements Filter {
-
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- // 初始化方法
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
- // 过滤逻辑
- System.out.println("Filter is processing the request...");
-
- // 继续处理请求
- chain.doFilter(request, response);
-
- // 在请求处理后执行一些操作
- System.out.println("Filter has processed the response...");
- }
-
- @Override
- public void destroy() {
- // 销毁方法
- }
- }
2.在 Spring Boot 应用的启动类或配置类中,加上 @ServletComponentScan 注解,以便 Spring Boot 能够扫描到过滤器:
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.boot.web.servlet.ServletComponentScan;
-
- @SpringBootApplication
- @ServletComponentScan
- public class YourSpringBootApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(YourSpringBootApplication.class, args);
- }
- }
在这个示例中,我们创建了一个名为 CustomFilter 的过滤器,并使用 @Component 注解将其标记为 Spring Bean。然后,在启动类中添加了 @ServletComponentScan 注解,以确保 Spring Boot 能够扫描到过滤器类。
1.在 Spring Boot 项目中实现一个拦截器非常简单,你只需要遵循以下步骤:
2.创建一个类,实现 org.springframework.web.servlet.HandlerInterceptor 接口,并重写相应的方法来实现拦截逻辑。
3.创建一个配置类,实现 org.springframework.web.servlet.config.annotation.WebMvcConfigurer 接口,并在其中注册你的拦截器。
1.创建一个拦截器类 CustomInterceptor,实现 org.springframework.web.servlet.HandlerInterceptor 接口:
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- import org.springframework.stereotype.Component;
- import org.springframework.web.servlet.HandlerInterceptor;
- import org.springframework.web.servlet.ModelAndView;
-
- @Component
- public class CustomInterceptor implements HandlerInterceptor {
-
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception {
- System.out.println("Interceptor preHandle method is called");
- return true; // 返回 true 表示继续处理请求,返回 false 表示中断请求处理
- }
-
- @Override
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
- ModelAndView modelAndView) throws Exception {
- System.out.println("Interceptor postHandle method is called");
- }
-
- @Override
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
- throws Exception {
- System.out.println("Interceptor afterCompletion method is called");
- }
- }
2.创建一个配置类 WebConfig,实现 WebMvcConfigurer 接口,并在其中注册拦截器:
- import org.springframework.context.annotation.Configuration;
- import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
- import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
- @Configuration
- public class WebConfig implements WebMvcConfigurer {
-
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- registry.addInterceptor(new CustomInterceptor())
- .addPathPatterns("/**"); // 拦截所有路径
- }
- }
在这个示例中,我们创建了一个名为 CustomInterceptor 的拦截器,并使用 @Component 注解将其标记为 Spring Bean。然后,我们创建了一个配置类 WebConfig,在其中通过实现 WebMvcConfigurer 接口,注册了拦截器并指定拦截的路径。
在Spring中,bean默认都是单例的,controller也是交给spring容器管理的一个bean,因此在SpringMVC中,Controller也是单例的,这样可以提高性能(减少创建对象和垃圾回收的时间)和资源利用率。这就意味着当多个请求同时访问同一个控制器Controller实例,如果控制器中的方法或变量是共享的话,就可能造成并发问题,导致数据不一致问题。
并发安全问题实例:
展示了一个控制器中可能存在的共享状态。这个示例中,我们将创建一个简单的计数器,控制器的方法会增加计数器的值,这样多个请求同时访问时可能会导致并发问题。
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.ResponseBody;
-
- @Controller
- public class SharedStateController {
-
- private int counter = 0; // 共享状态,可能导致并发问题
-
- @GetMapping("/incrementCounter")
- @ResponseBody
- public String incrementCounter() {
- counter++;
- return "Counter value: " + counter;
- }
- }
在这个示例中,SharedStateController 控制器类有一个 counter 实例变量,用于存储计数器的值。每次调用 /incrementCounter 路径的请求都会增加计数器的值。由于控制器默认是单例的,多个请求可能会同时访问和修改 counter 变量,从而导致并发问题。
解决这些并发安全问题的方法有:
1.避免共享状态: 在控制器中避免使用共享状态,尽量保持无状态的设计。如果必须使用共享状态,确保采用线程安全的方式进行访问和修改。
2.使用局部变量: 在方法内部使用局部变量而不是实例变量,这样可以避免多个请求之间共享数据。
3.同步机制synchronized: 对于需要共享状态的情况,可以使用同步机制来保证多个线程的安全访问。在方法或代码块中使用 synchronized 关键字来确保一次只有一个线程访问。
4.使用线程安全的数据结构: 如果需要在控制器中存储一些共享状态,可以使用线程安全的数据结构,如 ConcurrentHashMap,来保证并发访问的安全性。
5.控制器多例: 如果对并发安全性要求非常高,也可以将控制器配置为多例,这样每个请求都会创建一个新的控制器实例,避免共享状态问题。可以通过在控制器类上添加 @Scope("prototype") 注解来实现。
下面是每个解决方法的基础代码案例:
1.避免共享状态:
避免在控制器中使用共享状态,尽量保持无状态的设计。
- @Controller
- public class NoSharedStateController {
-
- @GetMapping("/simple")
- public String simple() {
- // 没有共享状态的操作
- return "simple";
- }
- }
2.使用局部变量:
在方法内部使用局部变量而不是实例变量,确保每个线程都有自己的变量。
- @Controller
- public class LocalVariableController {
-
- @GetMapping("/local")
- public String local() {
- int localVar = 0; // 局部变量,每个线程都有自己的副本
- // 使用 localVar 进行操作
- return "local";
- }
- }
3.同步机制synchronized:
使用 synchronized 关键字确保同一时间只有一个线程访问。
- @Controller
- public class SynchronizedController {
-
- private int sharedCounter = 0;
-
- @GetMapping("/syncIncrement")
- public synchronized String syncIncrement() {
- sharedCounter++;
- return "counter";
- }
- }
4.使用线程安全的数据结构:
使用线程安全的数据结构,如 ConcurrentHashMap。
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.GetMapping;
-
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.atomic.AtomicInteger;
-
- @Controller
- public class ThreadSafeDataStructureController {
-
- private ConcurrentHashMap
counterMap = new ConcurrentHashMap<>(); -
- @GetMapping("/threadSafe")
- public String threadSafe() {
- String key = "counterKey";
- counterMap.putIfAbsent(key, new AtomicInteger(0));
- AtomicInteger counter = counterMap.get(key);
- counter.incrementAndGet();
- return "counter";
- }
- }
5.控制器多例:
将控制器配置为多例,每个请求创建一个新的实例。
- import org.springframework.context.annotation.Scope;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.GetMapping;
-
- @Controller
- @Scope("prototype") //将控制器设置成多例
- public class PrototypeController {
-
- private int counter = 0;
-
- @GetMapping("/prototypeIncrement")
- public String prototypeIncrement() {
- counter++;
- return "counter";
- }
- }
@RequestMapping是一个通用的注解,用于接收HTTP请求映射到处理方法。它可以映射不同的HTTP请求(GET、POST、PUT、DELETE、PATCH等);
而@GetMapping则是@RequestMapping的一个特定用法,专门用来将HTTP的GET请求映射到处理方法;
-
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.ResponseBody;
-
- @Controller
- public class RequestMappingExampleController {
-
- @RequestMapping("/hello")
- @ResponseBody
- public String hello() {
- return "Hello, using @RequestMapping!";
- }
- }
在这个示例中,/hello 路径的 GET 请求将映射到 hello() 方法。
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.ResponseBody;
-
- @Controller
- public class GetMappingExampleController {
-
- @GetMapping("/greeting")
- @ResponseBody
- public String greeting() {
- return "Greetings, using @GetMapping!";
- }
- }
在这个示例中,/greeting 路径的 GET 请求将映射到 greeting() 方法,与 @RequestMapping 不同,@GetMapping 只处理 GET 请求。
会话:就是客户端和服务端的多次请求和响应的一个过程。
会话跟踪技术:在一次会话中,不同请求之间共享数据的技术。
突破口:数据保存在那儿。
Cookie[生命周期-从创建的时候开始计算]--(登录记住我的功能):
1.数据保存在客户端浏览器的会话跟踪技术。
2.数据不太安全。
3.数据大小【单个cookie不超过4k-20个cookie】有限制,并且保存的数据只能是字符串。
4.cookie可长期保存在客户端。
注:操作中文要进行编码和解码。
编码:URLEncoder.encode("四川成都","UTF-8")
解码:URLDecoder.decode(cookie.getValue(),"UTF-8")
Session【生命周期-从不操作的时候开始计算】(实现登录拦截--整个会话都可以显示用户名):
1.将数据保存在服务器端的会话跟踪技术。
2.数据相对安全,可以存储敏感的数据。
3.而且数据类型和大小没有限制。
4.随会话的结束而将存储的数据进行销毁。
但是如果服务器端保存的数据太多,会影响服务器的性能【所以服务器默认设置了Session的生命周期为30分钟】
拓展:HTTP是无状态的,就是说你这次访问服务器,关闭网页,再访问服务器,服务器是没有意识到又是你来访问。
那怎样保证将我们保持登录?这就需要使用Cookie技术进行存储用户名和密码。
说白了,cookie就是存储在浏览器的数据而已。
1.浏览器向服务器发送HTTP的请求。
2.服务器进行认证成功,就会以set-cookie【例:name:张三,value:1234】的方式将cookie传回给浏览器。
3.浏览器就会将cookie保存起来。
4.当后续浏览器再次请求服务器的时候,就会自动将cookie传递给服务器。
5.服务器解析cookie,验证用户信息。
1.当浏览器向服务器发送创建Session的请求的时候。服务器就会创建Session对象,然后为Session对象分配一个 jsessionid,再以Set-Cookie的方式将jsessionid传回给浏览器。
2.浏览器将 jsessionid 保存起来。
3.当后续浏览器再次访问服务器时,会自动的将jsessionid以cookie的方式传递给服务器。
4.服务器就可以根据jsessionid找到session对象,获取session中的数据验证用户信息。
以下是一个简化的代码示例,演示了 Cookie 和 Session 的执行原理。
假设有一个简单的 Web 应用,用户在登录页面输入用户名和密码进行登录,然后展示欢迎页面。
- import javax.servlet.http.Cookie;
- import javax.servlet.http.HttpServletResponse;
-
- @Controller
- public class CookieExampleController {
-
- @GetMapping("/loginWithCookie")
- public String loginWithCookie(HttpServletResponse response, Model model) {
- // 模拟用户登录成功,生成一个 Cookie
- Cookie userCookie = new Cookie("user", "john_doe");
- userCookie.setMaxAge(60 * 60 * 24); // 设置 Cookie 过期时间为一天
- response.addCookie(userCookie);
-
- model.addAttribute("message", "Logged in using Cookie!");
- return "welcome";
- }
-
- @GetMapping("/welcomeWithCookie")
- public String welcomeWithCookie(@CookieValue(name = "user", required = false) String user, Model model) {
- if (user != null) {
- model.addAttribute("message", "Welcome, " + user + "!");
- } else {
- model.addAttribute("message", "Please log in first.");
- }
- return "welcome";
- }
- }
- import javax.servlet.http.HttpSession;
-
- @Controller
- public class SessionExampleController {
-
- @GetMapping("/loginWithSession")
- public String loginWithSession(HttpSession session, Model model) {
- // 模拟用户登录成功,将用户名存入 Session
- session.setAttribute("user", "jane_smith");
-
- model.addAttribute("message", "Logged in using Session!");
- return "welcome";
- }
-
- @GetMapping("/welcomeWithSession")
- public String welcomeWithSession(HttpSession session, Model model) {
- String user = (String) session.getAttribute("user");
- if (user != null) {
- model.addAttribute("message", "Welcome, " + user + "!");
- } else {
- model.addAttribute("message", "Please log in first.");
- }
- return "welcome";
- }
- }
在这两个示例中,loginWithCookie 和 loginWithSession 方法模拟了用户登录成功后的操作。它们分别在 Cookie 和 Session 中存储用户信息。然后,welcomeWithCookie 和 welcomeWithSession 方法用于展示欢迎页面,从 Cookie 或 Session 中读取用户信息并显示。
PreparedStatement接口继承了Statement接口。
在java中,PreparedStatement和Statement都是用于执行sql查询和修改的接口。
但也有一些不同之处:
1.预编译和缓存:
“Statement”:每次执行SQL查询时,都需要将SQL字符串发送到数据库进行解析和编译,然后再执行。当需要多次执行相同的查询条件时,这样执行效率就比较低。
“PrepareStatement”:每次执行SQL查询时,SQL查询会被预编译并存储到数据库当中,就避免了每次都去数据库进行解析和编译,大大的提高了执行效率。
2.sql注入问题:
“Statement”:执行查询时,将参数值直接拼接到SQL字符串中,可能出现sql注入问题。
“PrepareStatement”:执行查询时,会预编译使用占位符(例如:“?”)来表示参数,然后通过方法设置参数值,可以防止sql注入问题。
get请求:
将请求数据在地址栏url进行显示。
数据不太安全。
请求数据大小有限制-大约2kb(2048个字符)
请求数据类型只能是文本字符,不能上传文件
post请求:
将请求数据存放在请求体request body中。
数据相对安全。
请求数据大小没有限制。
请求数据类型可以是任意类型,图片视频等,可以上传文件
Restful是一种接口编写规范。可以简单理解为:使用url请求地址定位资源,用HTTP动词(GET,POST。DELETE。PUT。PATCH)描述请求操作。
注意:区分一个请求是不是相同的请求:1 请求方式【HTTP动词】+url请求地址。
定义:Springboot是一个简化配置(文件)和快速搭建项目的全新框架,目的就是用来简化Spring应用的初始搭建和开发过程。
注意:SpringBoot不是用来替换ssm的,只是用来简化配置、快速搭建和部署的全新框架
优势:
简单而言:SpringBoot使编码更简单,使配置更简单,使部署更简单,使监控更简单。
快速启动:SpringBoot内置Web(tomcat)容器,快速启动一个web项目(main方法启动)不再每次都去等待tomcat启动。
简化配置:Spring Boot提供了一种快速使用Spring的方式,简化xml配置(Mybatis除外-就是Mapper中写sql语句的),使用注解@SpringBootApplication加在主启动类上面,提高开发效率
入门容易:SpringBoot继承了原有Spring框架的优秀基因,写代码还是ssm代码。
- /**
- * 课程的启动类
- * mapperscan在配置类中已经使用了
- * */
- //@SpringBootApplication(scanBasePackages = "cn.wmx") // 默认是扫描当前包及其子包,但是如果需要自定义扫描路径,就需要使用scanBasePackages
- @SpringBootApplication
- @EnableDiscoveryClient// @EnableEurekaClient 和 @EnableDiscoveryClient 的作用都是能够让注册中心发现、并扫描到该服务”
- // @EnableEurekaClient只适用于Eureka作为注册中心 @EnableDiscoveryClient 可以是其他注册中心。
- @EnableFeignClients // 开启feign接口的扫描
- @EnableCaching // 开启SpringCache[基于缓存的注解]
- public class CourseStarter {
- public static void main(String[] args) {
- SpringApplication.run(CourseStarter.class,args);
- }
- }
在 Spring Boot 项目中,你可以使用 @Value 注解、Environment 对象或者 @ConfigurationProperties 注解来获取配置文件中的内容。下面分别介绍这些方法的用法:
@Value 注解可以用来注入单个属性的值。你可以在需要获取配置值的字段或方法上使用该注解。
- @Component
- @Data
- public class PlayEduConfig {
-
- @Value("${edu.limiter.limit}")
- private Long limiterLimit;
- }
application.yml
- edu:
- core:
- testing: false
- limiter:
- duration: 60
- limit: 360
Environment 对象提供了一种在代码中访问配置属性的方法。
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.EnvironmentAware;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.core.env.Environment;
-
- @Configuration
- public class MyConfiguration implements EnvironmentAware {
- private Environment environment;
-
- @Autowired
- public void setEnvironment(Environment environment) {
- this.environment = environment;
- }
-
- public void someMethod() {
- String appName = environment.getProperty("edu.limiter.limit");
- // ...
- }
- }
@ConfigurationProperties 注解用于将配置属性映射到 Java 类中,然后通过 Spring Boot 自动将配置文件中的值注入到该类的字段中。
- import org.springframework.boot.context.properties.ConfigurationProperties;
- import org.springframework.stereotype.Component;
-
- @Component
- @ConfigurationProperties(prefix = "edu.limiter")
- public class MyAppProperties {
- private String limit;
- private String duration;
-
- // Getter and setters...
-
- // ...
- }
这些方法中,使用 @ConfigurationProperties 注解是一个更强大的选项,特别适用于需要一次性注入多个配置属性的情况。
我们使用了AOP(面向切面编程)的理念,通过自定义异常NotFoundException然后继承Exception。然后自定义一个名为ExceptionController类,类上加上注解@RestControllerAdvice(@ControllerAdvice 和 @ResponseBody 注解的结合,作用是:集中管理全部异常),自定义类中的方法上加上注解@ExceptionHandler(异常类.class-可以捕获的异常类),当@Controller注解下的接口出现异常就会进行匹配@ExceptionHandler(异常类.class)对应的异常类型,然后将错误信息和错误码进行封装返回给前台。这样就避免在Controller层写大量的try catch代码了。
下面是一个代码举例说明:
全局异常统一管理:
- /**
- *全局异常统一处理
- * 1.@RestControllerAdvice 的主要作用是集中管理全局异常处理
- * 2.@ExceptionHandler 注解标注的方法可以捕获和处理应用程序中抛出的异常
- **/
- @RestControllerAdvice
- @Slf4j
- public class ExceptionController {
-
-
- @ExceptionHandler(NotFoundException.class)
- public JsonResponse serviceExceptionHandler(NotFoundException e) {
- return JsonResponse.error(e.getMessage(), 404);
- }
-
- @ExceptionHandler(LimitException.class)
- public JsonResponse serviceExceptionHandler(LimitException e) {
- return JsonResponse.error("请稍后再试", 429);
- }
- }
- public class NotFoundException extends Exception {
- public NotFoundException() {
- super();
- }
-
- public NotFoundException(String message) {
- super(message);
- }
-
- public NotFoundException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public NotFoundException(Throwable cause) {
- super(cause);
- }
-
- protected NotFoundException(
- String message,
- Throwable cause,
- boolean enableSuppression,
- boolean writableStackTrace) {
- super(message, cause, enableSuppression, writableStackTrace);
- }
- }
业务代码:
- @GetMapping("/{id}")
- public JsonResponse edit(@PathVariable Integer id) throws NotFoundException {
- AdminUser adminUser = adminUserService.findOrFail(id);
- HashMap
data = new HashMap<>(); - data.put("user", adminUser);
- return JsonResponse.data(data);
- }
- @Override
- public AdminUser findOrFail(Integer id) throws NotFoundException {
- AdminUser user = getOne(query().getWrapper().eq("id", id));
- if (user == null) {
- throw new NotFoundException("管理员不存在");
- }
- return user;
- }
@SpringBootApplication注解用于标识当前类是SpringBoot的启动类。用于快速启动SpringBoot项目。@SpringBootApplication注解包含了以下三个注解的功能:
@ComponentScan注解:开启IOC自动扫描注解,默认扫描当前包及其子包中@Controller,@Service,@Repository,@Component等注解,并把这些bean加载到IOC容器当中。
@EnableAutoConfiguration注解:启用springboot自动配置,让SpringBoot根据项目的依赖和配置来自动配置Spring应用。
@SpringBootConfiguration注解:表示该类为springboot配置类。
spring-boot-starter-parent是SpringBoot的Maven父项目。
作用:提供给springboot统一的依赖管理和插件管理和一些常用配置,帮助开发者快速构建和管理SpringBoot项目。
pom.xml:
- <parent>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-parentartifactId>
- <version>3.1.1version>
- <relativePath/>
- parent>
作用:内置tomcat(可以快速启动项目)、SpringMVC的集成(快速搭建web层-表现层)、静态资源处理、模板引擎功能。让我们更专注于业务逻辑的开发。
这是Springboot的核心启动器,用于简化和加速SpringBoot项目的开发。
作用:
1依赖管理:Starter预定义了一组相关的依赖库,他会自动引入所需的依赖版本。
2自动配置:Starter包含了默认的配置项,从而减少了手动配置的工作。
3功能模块:Starter提供了一种按需求进行加载功能的方式,比如web、数据访问、安全等。
4.约定大于配置:Starter在一定程度上为项目提供了一些默认的约定。
在Springboot中,可以注解@Transactional来标记需要进行事务管理的方法,从而对数据库数据进行管理。