The Spring portfolio provides two parallel stacks. One is based on a Servlet API with Spring MVC and Spring Data constructs. The other is a fully reactive stack that takes advantage of Spring WebFlux and Spring Data’s reactive repositories. In both cases, Spring Security has you covered with native support for both stacks. https://spring.io/reactive
Spring产品组合提供了两个并行技术栈。一种基于带有 Spring MVC 和 Spring Data 结构的 Servlet API。另一个是完全响应式技术栈,该栈利用了 Spring WebFlux 和 Spring Data 的响应式存储库。在这两种情况下,Spring Security 都为两个堆栈提供了本机支持。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
User.java
public class User {
/**
* id
*/
private Integer id;
/**
* 姓名
*/
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
public User() {
}
}
UserRepository.java
@Repository
public class UserRepository {
// 生成id
private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
// 模拟内存数据库
private static final Map<Integer, User> USER_MAP = new HashMap<>();
public List<User> selectAll() {
return new ArrayList<>(USER_MAP.values());
}
public User getUserById(Integer id) {
return USER_MAP.get(id);
}
public User addUser(User user) {
if (Objects.isNull(user.getId())) {
user.setId(ID_GENERATOR.incrementAndGet());
}
USER_MAP.put(user.getId(), user);
return user;
}
public User update(User user) {
USER_MAP.put(user.getId(), user);
return user;
}
public User delete(Integer id) {
return USER_MAP.remove(id);
}
public boolean exist(User user) {
List<String> nameList = USER_MAP.values().stream().map(User::getName).collect(Collectors.toList());
return nameList.contains(user.getName());
}
}
UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public List<User> selectAll() {
return userRepository.selectAll();
}
@Override
public User getUserById(Integer id) {
return userRepository.getUserById(id);
}
@Override
public User addUser(User user) {
return userRepository.addUser(user);
}
@Override
public User update(User user) {
return userRepository.update(user);
}
@Override
public User delete(Integer id) {
return userRepository.delete(id);
}
@Override
public boolean exist(User user) {
return userRepository.exist(user);
}
}
UserController.java
@RestController
@RequestMapping(value = "/user")
public class UserController {
private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);
@Autowired
private UserService userService;
@RequestMapping(value = "/list", method = RequestMethod.GET)
public List<User> list() {
return userService.selectAll();
}
@RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public User get(@PathVariable Integer id) {
return userService.getUserById(id);
}
@RequestMapping(value = "/add", method = RequestMethod.POST)
public ResponseEntity<Void> create(@RequestBody User user, UriComponentsBuilder builder) {
if ("duplicated".equals(user.getName())) {
LOGGER.warn("the user already exist");
return new ResponseEntity<>(HttpStatus.ALREADY_REPORTED);
}
userService.addUser(user);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(builder.path("/user/get/{id}").buildAndExpand(user.getId()).toUri());
return new ResponseEntity<>(headers, HttpStatus.CREATED);
}
@RequestMapping(value = "/update", method = RequestMethod.PUT)
public User update(@RequestBody User user) {
return userService.update(user);
}
@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
public User delete(@PathVariable Integer id) {
return userService.delete(id);
}
}
spring-boot/spring-boot-03-webmvc
启动 SpringBoot03WebApplication.main 方法,在 spring-boot-03-webmvc.http 访问下列地址,观察输出信息是否符合预期。
### GET /user/list
GET http://localhost:8080/user/list
由于数据保存在内存中,最开始没有数据,所以返回为空。可以调用 /add 添加数据后再查询
### GET /user/get/{id}
GET http://localhost:8080/user/get/1
通过 id 查询同样为空,可以调用 /add 添加数据后再查询
### POST /user/add
POST http://localhost:8080/user/add
Content-Type: application/json
{
"name": "zhangsan"
}
这里响应码为 201,同时响应头中 location 设定为一个新的地址
### PUT /user/update
PUT http://localhost:8080/user/update
Content-Type: application/json
Accept: application/json
{
"id": 1,
"name": "lisi"
}
### DELETE /user/delete/{id}
DELETE http://localhost:8080/user/delete/1
DispatcherServlet 其实也是一个 HttpServlet,它的类图如下
在传统的 HttpServlet 中,它的生命周期包含 init、service、destroy,在 service 中一般有 doGet、doPost 分别来处理 get、post 请求。DispatcherServlet 即是在 HttpServlet 上面进行的扩展。
SpringMvc 的初始化时序图:
protected void initStrategies(ApplicationContext context) {
// 初始化上传组件,用于文件上传等
initMultipartResolver(context);
// 初始化本地化组件,用于国际化
initLocaleResolver(context);
// 初始化主题组件
initThemeResolver(context);
// 初始化处理器映射器
initHandlerMappings(context);
// 初始化处理器适配器
initHandlerAdapters(context);
// 初始化异常处理器
initHandlerExceptionResolvers(context);
// 初始化请求-视图名称翻译器
initRequestToViewNameTranslator(context);
// 初始化视图处理器
initViewResolvers(context);
// 初始化 FlashMapManager
initFlashMapManager(context);
}
SpringMvc 的运行时序图:
在一般的 Spring WebMvc 项目中,通常会在 web.xml 中配置好 DispatcherServlet,如下所示
<servlet>
<!-- 配置DispatcherServlet -->
<servlet-name>springMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定spring mvc配置文件位置 不指定使用默认情况 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-context.xml</param-value>
</init-param>
<!-- 设置启动顺序 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- ServLet 匹配映射 -->
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
那么,在 Spring Boot 项目中,DispatcherServlet 又是如何生效的呢?
其实,在 spring-boot-autoconfigure/META-INF/spring.factories 中有这样一个配置
这个 DispatcherServletAutoConfiguration 即是 DispatcherServlet 的自动装配类
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {
public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
@Configuration(proxyBeanMethods = false)
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
protected static class DispatcherServletConfiguration {
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails());
return dispatcherServlet;
}
}
// ...
}
3.SpringBoot学习(三)——WebMVC及其工作原理
原文:https://www.cnblogs.com/col-smile/p/13289378.html