Spring Boot提供了spring-boot-starter-web为Web开发予以支持,spring-boot-starter-web为我们提供了嵌入的Tomcat以及Spring MVC的依赖。与Web相关的自动配置存储在spring-boot-autoconfigure.jar的org.springframework.boot.web下,如下图所示:
org.springframework
spring-core
4.3.6.RELEASE
org.springframework
spring-beans
4.3.6.RELEASE
org.springframework
spring-webmvc
4.3.6.RELEASE
junit
junit
4.12
log4j
log4j
1.2.17
org.slf4j
slf4j-api
1.7.5
org.slf4j
jcl-over-slf4j
1.7.5
org.thymeleaf
thymeleaf
3.0.5.RELEASE
org.thymeleaf
thymeleaf-spring4
3.0.5.RELEASE
javax.servlet
jstl
1.2
package net.hw.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring4.view.ThymeleafView;
import org.thymeleaf.spring4.view.ThymeleafViewResolver;
/**
* Created by howard on 2017/4/4.
*/
@Configuration
@EnableWebMvc
@ComponentScan("net.hw.spring")
public class SpringMvcConfig extends WebMvcConfigurerAdapter {
// 定义Servlet容器模板解析器
@Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("/WEB-INF/classes/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
return templateResolver;
}
// 定义Spring模板引擎
@Bean
public SpringTemplateEngine springTemplateEngine() {
SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.setTemplateResolver(templateResolver());
return springTemplateEngine;
}
// 定义Thymeleaf视图解析器
@Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(springTemplateEngine());
viewResolver.setViewClass(ThymeleafView.class);
viewResolver.setOrder(1);
return viewResolver;
}
// 定义JSP视图解析器Bean
@Bean
public InternalResourceViewResolver internalResourceViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/classes/views/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewClass(JstlView.class);
viewResolver.setOrder(2);
return viewResolver;
}
}
package net.hw.spring.config;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
/**
* Created by howard on 2017/4/4.
*/
public class WebInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// 创建Web应用容器
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
// 注册Spring MVC配置类
context.register(SpringMvcConfig.class);
// 与当前ServletContext关联
context.setServletContext(servletContext);
// 注册Spring MVC的前端控制器(DispatcherServlet)
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
// 过滤一切资源请求
servlet.addMapping("/");
// 设置启动加载顺序
servlet.setLoadOnStartup(1);
}
}
package net.hw.spring.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Created by howard on 2017/4/3.
*/
@Controller
public class HelloController {
@RequestMapping("/")
public String home() {
return "index";
}
}
org.yaml
snakeyaml
1.18
package net.hw.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* Created by howard on 2017/4/4.
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private int id;
private String name;
private String gender;
private int age;
private String telephone;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
", telephone='" + telephone + '\'' +
'}';
}
}
package net.hw.controller;
import net.hw.bean.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Created by howard on 2017/4/2.
*/
@Controller
public class PersonController {
@Autowired
private Person person;
@RequestMapping("/showPerson")
public String showPerson(Model model) {
model.addAttribute("person", person);
return "showPerson";
}
}
显示个人信息
显示个人信息
编号:
姓名:
性别:
年龄:
电话:
package net.hw.bean;
/**
* Created by howard on 2017/4/4.
*/
public class Product {
private int id;
private String name;
private double price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
package net.hw.settings;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* Created by howard on 2017/4/4.
*/
@Component
@ConfigurationProperties(prefix = "book")
public class BookSettings {
private int id;
private String name;
private double price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
package net.hw.settings;
import net.hw.bean.Product;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Created by howard on 2017/4/4.
*/
@Component
@ConfigurationProperties(prefix = "warehouse")
public class WarehouseSettings {
List products;
public List getProducts() {
return products;
}
public void setProducts(List products) {
this.products = products;
}
}
package net.hw.controller;
import net.hw.settings.BookSettings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by howard on 2017/4/4.
*/
@RestController
public class BookController {
@Autowired
private BookSettings book;
@RequestMapping("/book")
public String book() {
return book.toString();
}
}
package net.hw.controller;
import net.hw.bean.Product;
import net.hw.settings.WarehouseSettings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
/**
* Created by howard on 2017/4/4.
*/
@Controller
public class WarehouseController {
@Autowired
private WarehouseSettings warehouse;
@RequestMapping("/showProducts")
public String showProducts(Model model) {
List products = warehouse.getProducts();
model.addAttribute("products", products);
System.out.println(products);
return "showProducts";
}
}
显示商品信息
商品列表
-
编号:
名称:
单价:
package net.hw;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class BootWebDemoApplication {
@RequestMapping("/")
public String home() {
return "Welcome to Spring Boot!
";
}
public static void main(String[] args) {
SpringApplication.run(BootWebDemoApplication.class, args);
}
}
@Bean
@ConditionalOnBean({ViewResolver.class})
@ConditionalOnMissingBean(
name = {"viewResolver"},
value = {ContentNegotiatingViewResolver.class}
)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
resolver.setOrder(-2147483648);
return resolver;
}
@Bean
@ConditionalOnBean({View.class})
@ConditionalOnMissingBean
public BeanNameViewResolver beanNameViewResolver() {
BeanNameViewResolver resolver = new BeanNameViewResolver();
resolver.setOrder(2147483637);
return resolver;
}
package net.hw.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
/**
* Created by howard on 2017/4/4.
*/
@Configuration
public class SpringConfig {
@Bean
public MappingJackson2JsonView jsonView() {
MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
return jsonView;
}
}
@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(this.mvcProperties.getView().getPrefix());
resolver.setSuffix(this.mvcProperties.getView().getSuffix());
return resolver;
}
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if(!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
Integer cachePeriod = this.resourceProperties.getCachePeriod();
if(!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(cachePeriod));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if(!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(this.resourceProperties.getStaticLocations()).setCachePeriod(cachePeriod));
}
}
}
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
public void addFormatters(FormatterRegistry registry) {
Iterator var2 = this.getBeansOfType(Converter.class).iterator();
while(var2.hasNext()) {
Converter formatter = (Converter)var2.next();
registry.addConverter(formatter);
}
var2 = this.getBeansOfType(GenericConverter.class).iterator();
while(var2.hasNext()) {
GenericConverter formatter1 = (GenericConverter)var2.next();
registry.addConverter(formatter1);
}
var2 = this.getBeansOfType(Formatter.class).iterator();
while(var2.hasNext()) {
Formatter formatter2 = (Formatter)var2.next();
registry.addFormatter(formatter2);
}
}
public void configureMessageConverters(List> converters) {
converters.addAll(this.messageConverters.getConverters());
}
@Bean
public XxServlet xxServlet () {
return new XxServlet();
}
@Bean
public YyFilter yyFilter() {
return new YyFilter();
}
@Bean
public ZzListener zzListener() {
return new ZzListener();
}
@Bean
public ServletRegistrationBean servletRegistrationBean() {
return new ServletRegistrationBean(new XxServlet(), "/xx/**");
}
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new YyFilter());
filterRegistrationBean.setOrder(2);
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean servletListenerRegistrationBean() {
return new ServletListenerRegistrationBean(new ZzListener());
}
server.port=8888
server.session.timeout=100
server.context-path=/index
server.tomcat.uri-encoding=GBK
server.tomcat.compression=on
package net.hw.config;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
/**
* Created by howard on 2017/4/5.
*/
@Component
public class CustomServletContainer implements EmbeddedServletContainerCustomizer {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setPort(8888);
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/404.html"));
}
}
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-tomcat
org.springframework.boot
spring-boot-starter-jetty
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-tomcat
org.springframework.boot
spring-boot-starter-undertow
package net.hw;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.xml.ws.spi.http.HttpContext;
@RestController
@SpringBootApplication
public class BootWebDemoApplication {
public static void main(String[] args) {
SpringApplication.run(BootWebDemoApplication.class, args);
}
@Bean
public Connector httpConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(8080);
connector.setSecure(false);
connector.setRedirectPort(8443);
return connector;
}
@Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
@Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(httpConnector());
return tomcat;
}
}
package net.hw.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
/**
* Created by howard on 2017/4/5.
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 广播式应该配置一个/topic消息代理
registry.enableSimpleBroker("/topic");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 注册一个STOMP的endpoint,并指定使用SockJS协议
registry.addEndpoint("/endpointSmart").withSockJS();
}
}
package net.hw.webmvc;
import net.hw.bean.SmartMessage;
import net.hw.bean.SmartResponse;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
/**
* Created by howard on 2017/4/5.
*/
@Controller
public class SmartController {
@MessageMapping("/welcome")
@SendTo("/topic/getResponse")
public SmartResponse say (SmartMessage message) throws Exception {
Thread.sleep(3000);
return new SmartResponse("Welcome, " + message.getName() + "!");
}
}
Spring Boot + WebSocket + 广播式
package net.hw.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Created by howard on 2017/4/9.
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/smart").setViewName("smart");
}
}
org.springframework.boot
spring-boot-starter-security
package net.hw.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* Created by howard on 2017/4/9.
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/login").permitAll() // 对"/", "/login"路径不拦截
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login") // 设置登录页面访问路径为/login
.defaultSuccessUrl("/chat") // 登录成功后转向/chat路径
.permitAll()
.and()
.logout()
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 在内存里配置两个用户
auth.inMemoryAuthentication()
.withUser("howard").password("11111").roles("USER")
.and()
.withUser("alice").password("22222").roles("USER");
}
@Override
public void configure(WebSecurity web) throws Exception {
// 不拦截静态资源
web.ignoring().antMatchers("/resources/static/**");
}
}
package net.hw.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
/**
* Created by howard on 2017/4/5.
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic", "/queue");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/endpointSmart").withSockJS();
registry.addEndpoint("/endpointChat").withSockJS();
}
}
package net.hw.webmvc;
import net.hw.bean.SmartMessage;
import net.hw.bean.SmartResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import java.security.Principal;
/**
* Created by howard on 2017/4/5.
*/
@Controller
public class SmartController {
@Autowired
private SimpMessagingTemplate messagingTemplate;
@MessageMapping("/chat")
public void handlerChat(Principal principal, String msg) {
if (principal.getName().equals("howard")) {
messagingTemplate.convertAndSendToUser("alice", "/queue/notifications",
principal.getName() + "-send: " + msg);
} else {
messagingTemplate.convertAndSendToUser("howard", "/queue/notifications",
principal.getName() + "-send: " + msg);
}
}
@MessageMapping("/welcome")
@SendTo("/topic/getResponse")
public SmartResponse say (SmartMessage message) throws Exception {
Thread.sleep(3000);
return new SmartResponse("Welcome, " + message.getName() + "!");
}
}
登录页面
无效的账号和密码
你已注销
Home
聊天室
package net.hw.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Created by howard on 2017/4/9.
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/smart").setViewName("smart");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/chat").setViewName("chat");
}
}