创建项目的时候勾选
webmysql两个模块
也可以使用yaml配置文件
spring: datasource: # 数据源基本配置 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/ssm_crud type: com.alibaba.druid.pool.DruidDataSource # 数据源其他配置 initialSize: 5 minIdle: 5 maxActive: 20 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 filters: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500在properties文件或者yml文件做好mybaits的映射
mybatis-plus: #除了mybatisplus提供给我们的自定义的crud功能,我们可能也需要写自己的crud,这时需要配置我们的mapper接口与mapper.xml的映射路径 mapper-locations: mybatis/**/*Mapper.xml typeAliasesPackage: com.myblogs.**.entity然后在UserMapper接口中写出新的查找方法,再在xml文件中配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.myblogs.test.mapper.UserMapper"> <select id="get" resultType="com.myblogs.test.entity.User"> select * from user where id = #{value} </select> </mapper>之后放到service中使用就好了。
springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件
–file:./config/
–file:./
–classpath:/config/
–classpath:/
优先级由高到底,高优先级的配置会覆盖低优先级的配置;
SpringBoot会从这四个位置全部加载主配置文件;互补配置;
我们还可以通过spring.config.location来改变默认的配置文件位置
项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定配置文件和默认加载的这些配置文件共同起作用形成互补配置;
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties
SpringBoot也可以从以下位置加载配置; 优先级从高到低;高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置
1.命令行参数
所有的配置都可以在命令行上进行指定
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc
多个配置用空格分开; --配置项=值
2.来自java:comp/env的JNDI属性
3.Java系统属性(System.getProperties())
4.操作系统环境变量
5.RandomValuePropertySource配置的random.*属性值
由jar包外向jar包内进行寻找;
优先加载带profile
6.jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件
7.jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件
再来加载不带profile
8.jar包外部的application.properties或application.yml(不带spring.profile)配置文件
9.jar包内部的application.properties或application.yml(不带spring.profile)配置文件
10.@Configuration注解类上的@PropertySource
11.通过SpringApplication.setDefaultProperties指定的默认属性
所有支持的配置加载来源;
参考官方文档
springboot默认配置符合我们的要求可以在项目中直接使用
Logger logger = LoggerFactory.getLogger(getClass()); @Test public void contextLoads() { //System.out.println(); //日志的级别; //由低到高 trace<debug<info<warn<error //可以调整输出的日志级别;日志就只会在这个级别以以后的高级别生效 logger.trace("这是trace日志..."); logger.debug("这是debug日志..."); //SpringBoot默认给我们使用的是info级别的,没有指定级别的就用SpringBoot默认规定的级别;root级别 logger.info("这是info日志..."); logger.warn("这是warn日志..."); logger.error("这是error日志..."); }可以在yml或者properties文件中设置日志输出等级来控制日志输出
#配置日志输出等级 logging: level: #配置根目录下的所有文件日志输出等级为info级别 root: info #配置所有com.hdeasy目录下的所有文件日志输出等级为debug com.hdeasy.hdeasyproject: debug 日志输出格式: %d表示日期时间, %thread表示线程名, %-5level:级别从左显示5个字符宽度 %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息, %n是换行符 --> %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%nSpringBoot修改日志的默认配置
logging.level.com.atguigu=trace #logging.path= # 不指定路径在当前项目下生成springboot.log日志 # 可以指定完整的路径; #logging.file=G:/springboot.log # 在当前磁盘的根路径下创建spring文件夹和里面的log文件夹;使用 spring.log 作为默认文件 logging.path=/spring/log # 在控制台输出的日志的格式 logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n # 指定文件中日志输出的格式 logging.pattern.file=%d{yyyy-MM-dd} === [%thread] === %-5level === %logger{50} ==== %msg%n logging.filelogging.pathExampleDescription(none)(none)只在控制台输出指定文件名(none)my.log输出日志到my.log文件(none)指定目录/var/log输出到指定目录的 spring.log 文件中logback.xml:直接就被日志框架识别了;
logback-spring.xml:日志框架就不直接加载日志的配置项,由SpringBoot解析日志配置,可以使用SpringBoot的高级Profile功能
<springProfile name="staging"> <!-- configuration to be enabled when the "staging" profile is active --> 可以指定某段配置只在某个环境下生效 </springProfile>如:
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <!-- 日志输出格式: %d表示日期时间, %thread表示线程名, %-5level:级别从左显示5个字符宽度 %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息, %n是换行符 --> <layout class="ch.qos.logback.classic.PatternLayout"> <springProfile name="dev"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern> </springProfile> <springProfile name="!dev"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%n</pattern> </springProfile> </layout> </appender>如果使用logback.xml作为日志配置文件,还要使用profile功能,会有以下错误
no applicable action for [springProfile]
可以按照slf4j的日志适配图,进行相关的切换;
slf4j+log4j的方式;
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <artifactId>logback-classic</artifactId> <groupId>ch.qos.logback</groupId> </exclusion> <exclusion> <artifactId>log4j-over-slf4j</artifactId> <groupId>org.slf4j</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency>切换为log4j2
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <artifactId>spring-boot-starter-logging</artifactId> <groupId>org.springframework.boot</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency>1)、引入webjar
<!--引入jquery-webjar-->在访问的时候只需要写webjars下面资源的名称即可 <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.5.1</version> </dependency>2)、springboot默认配置的静态资源映射文件夹
"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" "/":当前项目的根路径3)、springboot自动映射默认静态文件夹下的index.html作为主页面
访问localhost:8088会默认访问localhost:8088/index.html
4)、springboot默认配置网页图标为 **/favicon.ico在默认的静态文件夹目录中寻找;
#自己定义静态资源文件夹 #自己定义后自动定义的就么有用了 #自己定义静态资源文件夹之后系统配置的文件夹就会失效,需要的时候可以手动配置回来。 spring.resources.static-locations=classpath:/hello,classpath:/atguigu5)、引入模板引擎thymelea
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> <!--2.1.6--> </dependency> <!--切换thymeleaf版本--> <properties> <thymeleaf.version>3.0.9.RELEASE</thymeleaf.version> <!-- 布局功能的支持程序 thymeleaf3主程序 layout2以上版本 --> <!-- thymeleaf2 layout1--> <thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version> </properties>thymelea模板引擎在2.0版本之前校验规则比较严谨。而且不支持什么玩意来着忘记了,但是用2.x的引擎然后用3.x的thymeleaf就好了
只要我们把HTML页面放在classpath:/templates/,thymeleaf就能自动渲染;
使用:
1、导入thymeleaf的名称空间
<html lang="en" xmlns:th="http://www.thymeleaf.org">2、使用thymeleaf语法;
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>成功!</h1> <!--th:text 将div里面的文本内容设置为 --> <div th:text="${hello}">这是显示欢迎信息</div> </body> </html>具体语法参考官方文档
Spring Boot 自动配置好了SpringMVC
以下是SpringBoot对SpringMVC的默认配置:(WebMvcAutoConfiguration)
我们可以对springmvc进行扩展
可以在视图解析器的地方添加视图解析。
配置拦截器进行登录检查
/*** * 登录检查 */ public class LoginHandlerInterceptor implements HandlerInterceptor { //目标方法执行之前 /*** * preHandle:在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理; * postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView (这个博主就基本不怎么用了); * afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面); */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object logUser = request.getSession().getAttribute("logUser"); if(logUser == null){ //未登录,返回登录页面 request.setAttribute("msg","没有权限请先登录"); request.getRequestDispatcher("/index.html").forward(request,response); return false; }else{ //已经登录,放行请求 return true; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }拦截器配置完成后在webmvc中注册进去
package com.myblogs.test.config; import com.myblogs.test.compoent.LoginHandlerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.web.servlet.config.annotation.*; import java.nio.charset.Charset; import java.util.List; @Configuration public class MyMvcConfig implements WebMvcConfigurer { @Bean public WebMvcConfigurer webMvcConfigurer() { WebMvcConfigurer webMvc = new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { //配置跨域请求 registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE") .maxAge(3600) .allowCredentials(true); } @Override public void addViewControllers(ViewControllerRegistry registry) { //配置相应的视图解析器用来做转发和跳转 registry.addViewController("/main.html").setViewName("emp/dashboard"); registry.addViewController("/").setViewName("index"); registry.addViewController("/index.html").setViewName("index"); } @Override public void addInterceptors(InterceptorRegistry registry) { //拦截所以的访问会把静态资源一起拦截把静态资源文件夹全部除掉 registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html","/","/user/login","/webjars/**","/asserts/**"); } @Bean public HttpMessageConverter<String> responseBodyConverter() { StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8")); return converter; } @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { WebMvcConfigurer.super.configureMessageConverters(converters); converters.add(responseBodyConverter()); } @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer.favorPathExtension(false); } }; return webMvc; } }springboot默认配置好了错误页面,会相应error下的4XX和5XXhtml文件。
如果想要自定义错误页面信息需要做下面操作啊
1)、有模板引擎的情况下;error/状态码; 【将错误页面命名为 错误状态码.html 放在模板引擎文件夹里面的 error文件夹下】,发生此状态码的错误就会来到 对应的页面;
我们可以使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,精确优先(优先寻找精确的状态码.html);
页面能获取的信息;
timestamp:时间戳
status:状态码
error:错误提示
exception:异常对象
message:异常消息
errors:JSR303数据校验的错误都在这里
2)、没有模板引擎(模板引擎找不到这个错误页面),静态资源文件夹下找;
3)、以上都没有错误页面,就是默认来到SpringBoot默认的错误提示页面;
1)、自定义异常处理&返回定制json数据;
@ControllerAdvice public class MyExceptionHandler { @ResponseBody @ExceptionHandler(UserNotExistException.class) public Map<String,Object> handleException(Exception e){ Map<String,Object> map = new HashMap<>(); map.put("code","user.notexist"); map.put("message",e.getMessage()); return map; } } //没有自适应效果... 2)、转发到/error进行自适应响应效果处理
@ExceptionHandler(UserNotExistException.class) public String handleException(Exception e, HttpServletRequest request){ Map<String,Object> map = new HashMap<>(); //传入我们自己的错误状态码 4xx 5xx,否则就不会进入定制错误页面的解析流程 /** * Integer statusCode = (Integer) request .getAttribute("javax.servlet.error.status_code"); */ request.setAttribute("javax.servlet.error.status_code",500); map.put("code","user.notexist"); map.put("message",e.getMessage()); //转发到/error return "forward:/error"; }出现错误以后,会来到/error请求,会被BasicErrorController处理,响应出去可以获取的数据是由getErrorAttributes得到的(是AbstractErrorController(ErrorController)规定的方法);
1、完全来编写一个ErrorController的实现类【或者是编写AbstractErrorController的子类】,放在容器中;
2、页面上能用的数据,或者是json返回能用的数据都是通过errorAttributes.getErrorAttributes得到;
容器中DefaultErrorAttributes.getErrorAttributes();默认进行数据处理的;
自定义ErrorAttributes
//给容器中加入我们自己定义的ErrorAttributes @Component public class MyErrorAttributes extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) { Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace); map.put("company","atguigu"); return map; } }最终的效果:响应是自适应的,可以通过定制ErrorAttributes改变需要返回的内容
1、修改和server有关的配置(ServerProperties【也是EmbeddedServletContainerCustomizer】);
server.port=8081 server.context-path=/crud server.tomcat.uri-encoding=UTF-8 //通用的Servlet容器设置 server.xxx //Tomcat的设置 server.tomcat.xxx2、编写一个EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定制器;来修改Servlet容器的配置
//在springboot新版本中以前的Em.....类被下面的类代替了所以使用下面的代码才可以运行 @Bean //一定要将这个定制器加入到容器中 public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){ return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() { @Override public void customize(ConfigurableWebServerFactory factory) { factory.setPort(8083); } }; }由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件。
首先创建一个MyServerConfig类,然后在对应的文件夹中常见对应的servlet,linser,filter
@Configuration public class MyServerConfig { //注册listener类 @Bean public ServletListenerRegistrationBean myListener(){ ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener()); return registrationBean; } //注册filter @Bean public FilterRegistrationBean myFilter(){ FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new MyFilter()); registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet")); return registrationBean; } //注册servlet @Bean public ServletRegistrationBean myServlet(){ ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new Myservlet(),"/myServlet"); return servletRegistrationBean; } @Bean public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){ return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() { @Override public void customize(ConfigurableWebServerFactory factory) { factory.setPort(8083); } }; } }注册三大组件用以下方式
ServletRegistrationBean
//注册三大组件 @Bean public ServletRegistrationBean myServlet(){ ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet"); return registrationBean; } --------------------------------- //servlet类 package com.hdeasy.hdeasyspringboot03.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class Myservlet extends HttpServlet { //配置嵌入式的servlet容器 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello MyServlet"); } }FilterRegistrationBean
@Bean public FilterRegistrationBean myFilter(){ FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new MyFilter()); registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet")); return registrationBean; } -------------------- //filter类 package com.hdeasy.hdeasyspringboot03.filter; import javax.servlet.*; import java.io.IOException; public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("MyFilter process..."); filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } }ServletListenerRegistrationBean
@Bean public ServletListenerRegistrationBean myListener(){ ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener()); return registrationBean; } ------------------------- //listener类 package com.hdeasy.hdeasyspringboot03.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class MyListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("当前项目启动"); } @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("当前项目报销"); } }创建国际化的配置文件
然后配置国际化的文件路径
#指定国际化的配置文件在哪个文件夹 spring.messages.basename=i18n.index #开启springmvc的过滤 spring.mvc.hiddenmethod.filter.enabled=true为了实现点击切换国际化的方法编写一个类,然后注册到容器中
@Component public class MyError extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) { Map<String,Object>map=super.getErrorAttributes(webRequest,options); map.put("company","atguigu"); Map<String,Object> ext = (Map<String, Object>) webRequest.getAttribute("ext",0); map.put("ext",ext); return map; } }在某一个控制类中注入他
@Bean public LocaleResolver LocaleResolver(){ return new MyLocaleResolver(); }在配置之前先要把之前TestBlogsController里面的/user/login类注释掉,这样才可以使用shiro来控制登录验证。
@Controller public class shiroController { @PostMapping("/user/login") public String loginuser(String username, String password, Model model, HttpSession session){ System.out.println(username+password); //获取subject对象 Subject subjct = SecurityUtils.getSubject(); //封装数据 UsernamePasswordToken token = new UsernamePasswordToken(username,password); //注册用户 try{ subjct.login(token); System.out.println("注册成功了"); }catch (UnknownAccountException e) { model.addAttribute("msg","用户名不存在"); return "redirect:/login"; }catch (IncorrectCredentialsException e) { model.addAttribute("msg","密码错误"); // e.printStackTrace(); return "redirect:/login"; } session.setAttribute("logUser",username); return "redirect:/main.html"; } }