java框架之SpringBoot(7)-异常处理

前言

在 SpringBoot 项目中,默认情况下,使用浏览器访问一个不存在的地址会返回如下错误页面:

而当客户端未非浏览器时,错误信息则会以 json 数据返回,如下:

会出现如上效果的原因是 SpringBoot 针对错误消息做了自动配置,对应自动配置类为 org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration 。

自定义错误页

查看错误自动配置类会发现在该类中注册了如下组件:

ErrorPageCustomizer

@Bean
public ErrorPageCustomizer errorPageCustomizer() {
    return new ErrorPageCustomizer(this.serverProperties);
}

查看该组件类:

 1     private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {
 2 
 3         private final ServerProperties properties;
 4 
 5         protected ErrorPageCustomizer(ServerProperties properties) {
 6             this.properties = properties;
 7         }
 8 
 9         @Override
10         public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
11             ErrorPage errorPage = new ErrorPage(this.properties.getServletPrefix()
12                     + this.properties.getError().getPath());
13             errorPageRegistry.addErrorPages(errorPage);
14         }
15 
16         @Override
17         public int getOrder() {
18             return 0;
19         }
20 
21     }
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration.ErrorPageCustomizer

在第 10 行的 registerErrorPages 方法中,注册了一个错误页,错误页路径为 this.properties.getError().getPath() ,该值为

@Value("${error.path:/error}")
private String path = "/error";

即,一旦出现了 4xx 或 5xx 错误,该组件就会生效,可用其定制系统发生错误时的转发路径,默认情况下当前请求会转发到  /error 路径。

BasicErrorController

@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
    return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
            this.errorViewResolvers);
}

查看该组件类:

 1 package org.springframework.boot.autoconfigure.web;
 2 
 3 import java.util.Collections;
 4 import java.util.List;
 5 import java.util.Map;
 6 
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 
10 import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeStacktrace;
11 import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
12 import org.springframework.http.HttpStatus;
13 import org.springframework.http.MediaType;
14 import org.springframework.http.ResponseEntity;
15 import org.springframework.stereotype.Controller;
16 import org.springframework.util.Assert;
17 import org.springframework.web.bind.annotation.RequestMapping;
18 import org.springframework.web.bind.annotation.ResponseBody;
19 import org.springframework.web.servlet.ModelAndView;
20 
21 @Controller
22 @RequestMapping("${server.error.path:${error.path:/error}}")
23 public class BasicErrorController extends AbstractErrorController {
24 
25     private final ErrorProperties errorProperties;
26 
27     public BasicErrorController(ErrorAttributes errorAttributes,
28             ErrorProperties errorProperties) {
29         this(errorAttributes, errorProperties,
30                 Collections.<ErrorViewResolver>emptyList());
31     }
32 
33     public BasicErrorController(ErrorAttributes errorAttributes,
34             ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) {
35         super(errorAttributes, errorViewResolvers);
36         Assert.notNull(errorProperties, "ErrorProperties must not be null");
37         this.errorProperties = errorProperties;
38     }
39 
40     @Override
41     public String getErrorPath() {
42         return this.errorProperties.getPath();
43     }
44 
45     @RequestMapping(produces = "text/html")
46     public ModelAndView errorHtml(HttpServletRequest request,
47             HttpServletResponse response) {
48         HttpStatus status = getStatus(request);
49         Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
50                 request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
51         response.setStatus(status.value());
52         ModelAndView modelAndView = resolveErrorView(request, response, status, model);
53         return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
54     }
55 
56     @RequestMapping
57     @ResponseBody
58     public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
59         Map<String, Object> body = getErrorAttributes(request,
60                 isIncludeStackTrace(request, MediaType.ALL));
61         HttpStatus status = getStatus(request);
62         return new ResponseEntity<Map<String, Object>>(body, status);
63     }
64 
65     protected boolean isIncludeStackTrace(HttpServletRequest request,
66             MediaType produces) {
67         IncludeStacktrace include = getErrorProperties().getIncludeStacktrace();
68         if (include == IncludeStacktrace.ALWAYS) {
69             return true;
70         }
71         if (include == IncludeStacktrace.ON_TRACE_PARAM) {
72             return getTraceParameter(request);
73         }
74         return false;
75     }
76 
77     protected ErrorProperties getErrorProperties() {
78         return this.errorProperties;
79     }
80 
81 }
org.springframework.boot.autoconfigure.web.BasicErrorController

可以看到该组件实际上是一个控制器,用来处理路径为配置中定义的 "${server.error.path:${error.path:/error}}" 请求,如果 server.error 和 error.path 都没有配置,则默认处理路径为 /error 的请求。

控制器中有两个响应方法,分别为第 46 行的 errorHtml 方法和第 58 行的 error 方法,它们都是用来处理路径为 /error 的请求,但 errorHtml 方法返回的错误消息是一个 html 页面,而 error 方法是返回的错误消息是一个 json 数据。通过 @RequestMapping 注解中的 produces 属性来区分客户端需要的错误消息类型,即根据客户端的 accept 请求头区分。具体以哪个页面作为错误页则可看到在第 52 行的 resolveErrorView 方法:

 1 protected ModelAndView resolveErrorView(HttpServletRequest request,
 2         HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
 3     for (ErrorViewResolver resolver : this.errorViewResolvers) {
 4         ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
 5         if (modelAndView != null) {
 6             return modelAndView;
 7         }
 8     }
 9     return null;
10 }
org.springframework.boot.autoconfigure.web.AbstractErrorController#resolveErrorView

可以看到,该方法时遍历容器中所有的错误视图解析器,如果解析器解析当前请求返回的 modelAndView 不为空,则以该 modelAndView 作为错误页的响应。即:以哪个页面作为错误页是由错误视图解析器的 resolveErrorView 方法的返回值决定。

DefaultErrorViewResolver

@Bean
@ConditionalOnBean(DispatcherServlet.class)
@ConditionalOnMissingBean
public DefaultErrorViewResolver conventionErrorViewResolver() {
    return new DefaultErrorViewResolver(this.applicationContext,
            this.resourceProperties);
}

这是默认配置的错误视图解析器,查看它的 resolveErrorView 方法:

 1 @Override
 2 public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
 3         Map<String, Object> model) {
 4     // 传入字符串形式的状态码
 5     ModelAndView modelAndView = resolve(String.valueOf(status), model);
 6     if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
 7         modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
 8     }
 9     return modelAndView;
10 }
11 
12 private ModelAndView resolve(String viewName, Map<String, Object> model) {
13     String errorViewName = "error/" + viewName;  // 如:error/404
14     TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
15             .getProvider(errorViewName, this.applicationContext);
16     if (provider != null) { // 如果模板引擎解析器可解析则返回模板视图
17         return new ModelAndView(errorViewName, model);
18     }
19     // 模板引擎不可解析时
20     return resolveResource(errorViewName, model);
21 }
22 
23 private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
24     for (String location : this.resourceProperties.getStaticLocations()) { // 遍历静态资源文件夹
25         try {
26             Resource resource = this.applicationContext.getResource(location); // 获取静态资源
27             resource = resource.createRelative(viewName + ".html");  // 如:error/404.html
28             if (resource.exists()) { // 判断对应资源是否存在
29                 return new ModelAndView(new HtmlResourceView(resource), model);  // 如果存在则返回对应 html 视图
30             }
31         }
32         catch (Exception ex) {
33         }
34     }
35     return null;
36 }
org.springframework.boot.autoconfigure.web.DefaultErrorViewResolver#resolveErrorView

通过上述代码可以看到,当请求出现错误时,错误视图解析器会在模板路径及静态文件夹路径下寻找以该错误对应状态码命名的 html 页面作为错误响应视图。比如错误代码为 404,那么默认情况下将会寻找在 templates 和 static 等静态资源文件夹下的 error/404.html 页面作为响应页。我们还可以通过使用 4xx.html 和 5xx.html 作为模板页或静态页分别来匹配以 4 开头和 5 开头的错误让其作为该错误的响应页。从 org.springframework.boot.autoconfigure.web.BasicErrorController#errorHtml 方法的返回值可以看到,如果在模板文件夹和静态文件夹下都没有找到对应的错误页,那么将会返回 new ModelAndView("error", model) 对象,而这个 error 视图在错误自动配置类中中已经配置好了:

 1 @Configuration
 2 @ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", matchIfMissing = true)
 3 @Conditional(ErrorTemplateMissingCondition.class)
 4 protected static class WhitelabelErrorViewConfiguration {
 5 
 6     private final SpelView defaultErrorView = new SpelView(
 7             "<html><body><h1>Whitelabel Error Page</h1>"
 8                     + "<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>"
 9                     + "<div id='created'>${timestamp}</div>"
10                     + "<div>There was an unexpected error (type=${error}, status=${status}).</div>"
11                     + "<div>${message}</div></body></html>");
12 
13     @Bean(name = "error")
14     @ConditionalOnMissingBean(name = "error")
15     public View defaultErrorView() {
16         return this.defaultErrorView;
17     }
18 
19     @Bean
20     @ConditionalOnMissingBean(BeanNameViewResolver.class)
21     public BeanNameViewResolver beanNameViewResolver() {
22         BeanNameViewResolver resolver = new BeanNameViewResolver();
23         resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
24         return resolver;
25     }
26 }
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration.WhitelabelErrorViewConfiguration

DefaultErrorAttributes

@Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
    return new DefaultErrorAttributes();
}

如上我们只说明了错误页的显示规则,那错误页的消息又是从何而来呢?回头看到 org.springframework.boot.autoconfigure.web.BasicErrorController#errorHtml 方法:

 1 @RequestMapping(produces = "text/html")
 2 public ModelAndView errorHtml(HttpServletRequest request,
 3         HttpServletResponse response) {
 4     HttpStatus status = getStatus(request);
 5     Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
 6             request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
 7     response.setStatus(status.value());
 8     ModelAndView modelAndView = resolveErrorView(request, response, status, model);
 9     return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
10 }
org.springframework.boot.autoconfigure.web.BasicErrorController#errorHtml

可以看到返回的 model 的数据为 getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)) 方法的返回值,查看该方法:

1 protected Map<String, Object> getErrorAttributes(HttpServletRequest request,
2         boolean includeStackTrace) {
3     RequestAttributes requestAttributes = new ServletRequestAttributes(request);
4     return this.errorAttributes.getErrorAttributes(requestAttributes,
5             includeStackTrace);
6 }
org.springframework.boot.autoconfigure.web.AbstractErrorController#getErrorAttributes

继续查看 this.errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace) 方法:

 1 @Override
 2 public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
 3         boolean includeStackTrace) {
 4     Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();
 5     errorAttributes.put("timestamp", new Date());
 6     addStatus(errorAttributes, requestAttributes);
 7     addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);
 8     addPath(errorAttributes, requestAttributes);
 9     return errorAttributes;
10 }
11 
12 private void addStatus(Map<String, Object> errorAttributes,
13         RequestAttributes requestAttributes) {
14     Integer status = getAttribute(requestAttributes,
15             "javax.servlet.error.status_code");
16     if (status == null) {
17         errorAttributes.put("status", 999);
18         errorAttributes.put("error", "None");
19         return;
20     }
21     errorAttributes.put("status", status);
22     try {
23         errorAttributes.put("error", HttpStatus.valueOf(status).getReasonPhrase());
24     }
25     catch (Exception ex) {
26         errorAttributes.put("error", "Http Status " + status);
27     }
28 }
29 
30 private void addErrorDetails(Map<String, Object> errorAttributes,
31         RequestAttributes requestAttributes, boolean includeStackTrace) {
32     Throwable error = getError(requestAttributes);
33     if (error != null) {
34         while (error instanceof ServletException && error.getCause() != null) {
35             error = ((ServletException) error).getCause();
36         }
37         errorAttributes.put("exception", error.getClass().getName());
38         addErrorMessage(errorAttributes, error);
39         if (includeStackTrace) {
40             addStackTrace(errorAttributes, error);
41         }
42     }
43     Object message = getAttribute(requestAttributes, "javax.servlet.error.message");
44     if ((!StringUtils.isEmpty(message) || errorAttributes.get("message") == null)
45             && !(error instanceof BindingResult)) {
46         errorAttributes.put("message",
47                 StringUtils.isEmpty(message) ? "No message available" : message);
48     }
49 }
50 
51 private void addErrorMessage(Map<String, Object> errorAttributes, Throwable error) {
52     BindingResult result = extractBindingResult(error);
53     if (result == null) {
54         errorAttributes.put("message", error.getMessage());
55         return;
56     }
57     if (result.getErrorCount() > 0) {
58         errorAttributes.put("errors", result.getAllErrors());
59         errorAttributes.put("message",
60                 "Validation failed for object='" + result.getObjectName()
61                         + "'. Error count: " + result.getErrorCount());
62     }
63     else {
64         errorAttributes.put("message", "No errors");
65     }
66 }
67 
68 private void addStackTrace(Map<String, Object> errorAttributes, Throwable error) {
69     StringWriter stackTrace = new StringWriter();
70     error.printStackTrace(new PrintWriter(stackTrace));
71     stackTrace.flush();
72     errorAttributes.put("trace", stackTrace.toString());
73 }
74 
75 private void addPath(Map<String, Object> errorAttributes,
76         RequestAttributes requestAttributes) {
77     String path = getAttribute(requestAttributes, "javax.servlet.error.request_uri");
78     if (path != null) {
79         errorAttributes.put("path", path);
80     }
org.springframework.boot.autoconfigure.web.DefaultErrorAttributes#getErrorAttributes

通过上述代码我们可以知道在错误页中我们可以使用如下错误信息:

timestamp:时间戳
status:状态码
error:错误提示
exception:异常对象
message:异常信息
errors:JSR303 数据校验错误信息

自定义错误信息

上述已经描述了我们如何使用自定义的错误页,但是使用的错误信息还依旧是 SpringBoot 默认配置的,如果我们想要自己定制错误信息,则可通过如下方式。

方便下面测试先编写如下异常类及控制器:

package com.springboot.webdev2.ex;

public class MyException extends RuntimeException {
    public MyException() {
        super("运行期间出异常了");
    }
}
com.springboot.webdev2.ex.MyException
package com.springboot.webdev2.controller;

import com.springboot.webdev2.ex.MyException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class TestController {

    @RequestMapping("test")
    public void test1(){
        throw new MyException();
    }
}
com.springboot.webdev2.controller.TestController

方式一:自定义异常处理器

 1 package com.springboot.webdev2.component;
 2 
 3 import com.springboot.webdev2.ex.MyException;
 4 import org.springframework.web.bind.annotation.ControllerAdvice;
 5 import org.springframework.web.bind.annotation.ExceptionHandler;
 6 import org.springframework.web.bind.annotation.ResponseBody;
 7 
 8 import java.util.HashMap;
 9 import java.util.Map;
10 
11 @ControllerAdvice
12 public class MyExceptionHandler {
13 
14     @ResponseBody
15     @ExceptionHandler(MyException.class)
16     public Map<String,Object> handleException(Exception e){
17         Map<String, Object> map = new HashMap<>();
18         map.put("code", "myCode");
19         map.put("msg", "自定义的异常");
20         return map;
21     }
22 }

com.springboot.webdev2.component.MyExceptionHandler

该方式是 SpringMVC 提供的异常处理方式,缺点:使用该方式失去了 SpringBoot 本身的根据客户端的不同自适应响应数据类型的功能。

方式二:转发到错误处理路径

我们已经知道默认情况下出现异常 SpringBoot 会将请求转发到 /error ,那么如果我们通过异常处理器手动转发到该路径,并可手动将我们需要的错误信息放入请求域,我们就可以解决方式一的缺点并且可以在错误页使用我们自己的错误信息了。

package com.springboot.webdev2.component;

import com.springboot.webdev2.ex.MyException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class MyExceptionHandler {

    @ExceptionHandler(MyException.class)
    public String handleException(Exception e, HttpServletRequest request){
        // SpringBoot 默认使用的状态码就是请求域中的 javax.servlet.error.status_code
        request.setAttribute("javax.servlet.error.status_code", 400);
        Map<String, Object> map = new HashMap<>();
        map.put("code", "myCode");
        map.put("msg", "自定义的异常");
        request.setAttribute("ext", map);
        return "forward:/error";
    }
}
com.springboot.webdev2.component.MyExceptionHandler
<!DOCTYPE html>
<html lang="cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>[[${status}]]</h1>
    <h2>[[${message}]]</h2>
    <!--请求域中取错误信息-->
    <h2>[[${ext.msg}]]</h2>
</body>
</html>

templates/error/4xx.html

可以发现,该方式依旧有一个缺点:放入请求域中的数据未被序列化,所以只可在转发到的模板页中取到,而在客户端是非浏览器时是拿不到自定义的错误信息的。

方式三:自定义错误处理控制器

出现异常时 SpringBoot 会将请求转发到 /error ,而处理该请求的控制器为 BaseErrorController  ,查看该控制器注册信息我们也可以知道,当我们自己定义一个 org.springframework.boot.autoconfigure.web.ErrorController 组件注册到容器中时,那么默认的 BasicErrorController 就不生效了,所以我们可以在自定义的错误处理控制器中根据我们的需要取到我们合适的信息返回。该方式比较复杂,明显不合适,了解即可,略过。

方式四:自定义ErrorAttributes

通过查看 org.springframework.boot.autoconfigure.web.BasicErrorController 我们已经知道,不管是响应 html 还是 json 错误信息,它们的错误信息都是通过 this.errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace) 方法取到,而 this.errorAttributes 对应的组件实际上在错误自动配置类中已经注册,即 DefaultErrorAttributes ,所以我们可以自定义一个的 org.springframework.boot.autoconfigure.web.ErrorAttributes 组件注册到容器中,重写它的 getErrorAttributes 方法,通过手动取得自定义的错误信息返回即可。

package com.springboot.webdev2.component;

import org.springframework.boot.autoconfigure.web.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;

import java.util.Map;

@Component
public class MyErrorAttributes extends DefaultErrorAttributes {

    @Override
    public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
        Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
        errorAttributes.put("ext", requestAttributes.getAttribute("ext", RequestAttributes.SCOPE_REQUEST));
        return errorAttributes;
    }
}
com.springboot.webdev2.component.MyErrorAttributes
package com.springboot.webdev2.component;

import com.springboot.webdev2.ex.MyException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class MyExceptionHandler {

    @ExceptionHandler(MyException.class)
    public String handleException(Exception e, HttpServletRequest request){
        // SpringBoot 默认使用的状态码就是请求域中的 javax.servlet.error.status_code
        request.setAttribute("javax.servlet.error.status_code", 400);
        Map<String, Object> map = new HashMap<>();
        map.put("code", "myCode");
        map.put("msg", "自定义的异常");
        request.setAttribute("ext", map);
        return "forward:/error";
    }
}
com.springboot.webdev2.component.MyExceptionHandler
<!DOCTYPE html>
<html lang="cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>[[${status}]]</h1>
    <h2>[[${message}]]</h2>
    <!--请求域中取错误信息-->
    <h2>[[${ext.msg}]]</h2>
</body>
</html>

templates/error/4xx.html

转载于:https://www.cnblogs.com/zze46/p/10593131.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是使用 Spring Boot 和 MyBatis-Plus 实现登录接口的基本步骤: 1. 添加 MyBatis-Plus 和 Spring Security 依赖: ```xml <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 2. 创建 User 实体类,并使用 @TableName 注解指定对应的数据库表名: ```java import com.baomidou.mybatisplus.annotation.TableName; @TableName("user") public class User { private Long id; private String username; private String password; // getter/setter 略 } ``` 3. 创建 UserMapper 接口,继承 BaseMapper<User> 接口: ```java import com.baomidou.mybatisplus.core.mapper.BaseMapper; public interface UserMapper extends BaseMapper<User> { } ``` 4. 创建 UserDetailsService 实现类,实现 loadUserByUsername 方法,根据用户名查询用户信息: ```java import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.example.demo.entity.User; import com.example.demo.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.User.UserBuilder; import org.springframework.stereotype.Service; @Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("username", username); User user = userMapper.selectOne(wrapper); if (user == null) { throw new UsernameNotFoundException("用户不存在"); } UserBuilder builder = org.springframework.security.core.userdetails.User.withUsername(username); builder.password(user.getPassword()); builder.roles("USER"); return builder.build(); } } ``` 5. 创建 LoginController 类,处理登录请求: ```java import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class LoginController { private final AuthenticationManager authenticationManager; private final UserDetailsService userDetailsService; public LoginController(AuthenticationManager authenticationManager, UserDetailsService userDetailsService) { this.authenticationManager = authenticationManager; this.userDetailsService = userDetailsService; } @PostMapping("/login") public String login(@RequestBody LoginRequest loginRequest) { Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())); SecurityContextHolder.getContext().setAuthentication(authentication); UserDetails userDetails = userDetailsService.loadUserByUsername(loginRequest.getUsername()); return "登录成功,欢迎 " + userDetails.getUsername(); } } ``` 6. 创建 LoginRequest 类,用于接收登录请求的用户名和密码: ```java public class LoginRequest { private String username; private String password; // getter/setter 略 } ``` 以上就是使用 Spring Boot 和 MyBatis-Plus 实现登录接口的基本步骤。在实现过程中 ### 回答2: Spring Boot是一个用于创建独立的、生产级别的基于Spring的应用程序的框架。MyBatis-Plus是一个基于MyBatis的增强工具,使得使用MyBatis更加便捷。下面是一个使用Spring Boot和MyBatis-Plus实现登录接口的示例: 1. 首先,需要创建一个实体类来表示用户数据,例如User实体类,其中包含属性id、username和password。 2. 创建一个Mapper接口来定义各种数据库操作,例如UserMapper接口。使用MyBatis-Plus的扩展接口BaseMapper可以减少手动编写SQL语句的工作量,它已经包含了一些常见的数据库操作方法,如selectById、selectList、insert、update等。 3. 在application.properties文件中配置数据库连接信息,包括数据库URL、用户名和密码。 4. 创建一个Service类,例如UserService类,用于处理业务逻辑。可以使用@Autowired注解将UserMapper注入到UserService类中,以便调用数据库操作。 5. 实现登录接口,可以创建一个Controller类,例如LoginController类。在其中定义一个login方法,用于接收前端传来的用户名和密码,然后调用UserService的方法进行用户验证。如果验证成功,则返回一个表示登录成功的状态码和一个token,否则返回一个表示登录失败的状态码。 6. 在登录成功后,可以将token保存在前端的localStorage或sessionStorage中。在后续的请求中,前端可以将token放在请求头中发送给服务器,以完成用户认证。 以上是一个简单的使用Spring Boot和MyBatis-Plus实现登录接口的示例。当然,在实际项目中,可能还需要添加很多其他的功能,如密码加密、验证码校验、异常处理等。但这个示例可以帮助你了解如何使用Spring Boot和MyBatis-Plus构建一个登录接口。 ### 回答3: Spring Boot和MyBatis-Plus是一种常见的Java开发框架和库,用于快速构建基于Spring框架和MyBatis持久层的应用程序。下面是一个简单的登录接口实现示例: 首先,我们需要创建一个用户实体类,用来表示用户的登录信息。该类可以包含用户名和密码等字段。 然后,在控制器类中创建一个登录的请求处理方法,该方法使用@PostMapping注解,表示处理POST请求。通过@RequestParam注解,获取前端传递的用户名和密码参数。接着,通过MyBatis-Plus提供的查询条件构造器,使用lambda表达式查询数据库中是否存在匹配的用户名和密码。如果存在匹配的用户,则返回登录成功的信息;否则,返回登录失败的信息。 接下来,我们可以配置一个拦截器或者过滤器,对登录接口进行访问权限的控制。比如,只有已登录的用户才能访问该接口。 最后,我们可以使用Postman等工具测试登录接口。通过发送POST请求,传递用户名和密码参数,即可获取登录结果。 需要注意的是,以上仅为登录接口的实现示例,实际应用中可能还需要添加校验、加密等功能,以增强安全性。 总之,Spring Boot和MyBatis-Plus的结合可以简化开发流程,提高开发效率,实现功能强大的登录接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值