• springboot


    springboot笔记

    搭建环境工具

    sts,右击,选中Web,DevTools

    配置文件

    springboot中,哪些参数可以进行自定义配置,配置参数是什么,在application.properties配置文件中,自定义参数的格式什么样的,我们可以参考spring-boot-autoconfigure-2.0.3.RELEASE.jar。以配置数据源为例子:

    	@ConfigurationProperties(prefix = "spring.datasource")
    	public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
    		private String driverClassName;
    
    		/**
    		 * JDBC URL of the database.
    		 */
    		private String url;
    	
    		/**
    		 * Login username of the database.
    		 */
    		private String username;
    	
    		/**
    		 * Login password of the database.
    		 */
    		private String password;
    	}
    

    我们在application.properties配置文件中,以spring.datasource作为key的前缀,我们配置参数时,key为 spring.datasource.url=

    • 置文件的生效顺序,会对值进行覆盖:

      1. @TestPropertySource 注解
      2. 命令行参数
      3. Java系统属性(System.getProperties())
      4. 操作系统环境变量
      5. 只有在random.*里包含的属性会产生一个RandomValuePropertySource
      6. 在打包的jar外的应用程序配置文件(application.properties,包含YAML和profile变量)
      7. 在打包的jar内的应用程序配置文件(application.properties,包含YAML和profile变量)
      8. 在@Configuration类上的@PropertySource注解
      9. 默认属性(使用SpringApplication.setDefaultProperties指定 application.properties)
    • 配置随机值

      1. roncoo.secret=${random.value}
      2. roncoo.number=${random.int}
      3. roncoo.bignumber=${random.long}
      4. roncoo.number.less.than.ten=${random.int(10)}
      5. roncoo.number.in.range=${random.int[1024,65536]}

      读取使用注解:@Value(value = "${roncoo.secret}") 注:出现黄点提示,是要提示配置元数据,可以不配置

    • 属性占位符

      当application.properties里的值被使用时,它们会被存在的Environment过滤,所以你能够引用先前定义的值(比如,系统属性)。
      roncoo.name=www.roncoo.com

      roncoo.desc=${roncoo.name} is a domain name

    • Application属性文件,按优先级排序,位置高的将覆盖位置低的

      1. 当前目录下的一个/config子目录
      2. 当前目录
      3. 一个classpath下的/config包
      4. classpath根路径(root)

        这个列表是按优先级排序的(列表中位置高的将覆盖位置低的)
    • 配置应用端口和其他配置的介绍

      端口配置:server.port=8090

      时间格式化:spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

      时区设置:spring.jackson.time-zone=Asia/Chongqing

    • 使用YAML代替Properties
      注意写法:冒号后要加个空格

    日志文件配置

    • spring boot默认会加载classpath:logback-spring.xml或者classpath:logback-spring.groovy

    • 使用自定义配置文件,在application.properties中配置方式为:
      logging.config=classpath:logback-roncoo.xml
      注意:不要使用logback这个来命名,否则spring boot将不能完全实例化

    • 日志文件配置

      
      
      	<?xml version="1.0" encoding="UTF-8"?>
      	<configuration>
      
      		<!-- 文件输出格式 -->
      		<property name="PATTERN" value="%-12(%d{yyyy-MM-dd HH:mm:ss.SSS}) |-%-5level [%thread] %c [%L] -| %msg%n" />
      		<!-- test文件路径 -->
      		<property name="TEST_FILE_PATH" value="c:/opt/roncoo/logs" />
      		<!-- pro文件路径 -->
      		<property name="PRO_FILE_PATH" value="/opt/roncoo/logs" />
      
      		<!-- 开发环境 -->
      		<springProfile name="dev">
      			<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
      				<encoder>
      					<pattern>${PATTERN}</pattern>
      				</encoder>
      			</appender>
      			
      			<logger name="com.roncoo.education" level="debug"/>
      	
      			<root level="info">
      				<appender-ref ref="CONSOLE" />
      			</root>
      		</springProfile>
      
      		<!-- 测试环境 -->
      		<springProfile name="test">
      			<!-- 每天产生一个文件 -->
      			<appender name="TEST-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      				<!-- 文件路径 -->
      				<file>${TEST_FILE_PATH}</file>
      				<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      					<!-- 文件名称 -->
      					<fileNamePattern>${TEST_FILE_PATH}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
      					<!-- 文件最大保存历史数量 -->
      					<MaxHistory>100</MaxHistory>
      				</rollingPolicy>
      				
      				<layout class="ch.qos.logback.classic.PatternLayout">
      					<pattern>${PATTERN}</pattern>
      				</layout>
      			</appender>
      			
      			<root level="info">
      				<appender-ref ref="TEST-FILE" />
      			</root>
      		</springProfile>
      
      		<!-- 生产环境 -->
      		<springProfile name="prod">
      			<appender name="PROD_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      				<file>${PRO_FILE_PATH}</file>
      				<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      					<fileNamePattern>${PRO_FILE_PATH}/warn.%d{yyyy-MM-dd}.log</fileNamePattern>
      					<MaxHistory>100</MaxHistory>
      				</rollingPolicy>
      				<layout class="ch.qos.logback.classic.PatternLayout">
      					<pattern>${PATTERN}</pattern>
      				</layout>
      			</appender>
      			
      			<root level="warn">
      				<appender-ref ref="PROD_FILE" />
      			</root>
      		</springProfile>
      
      	</configuration>
      

    模板引擎

    一. spring boot的web应用开发,是基于spring mvc

    二. Spring boot 在spring默认基础上,自动配置添加了以下特性:

    1. 包含了ContentNegotiatingViewResolver和BeanNameViewResolver beans。
    2. 对静态资源的支持,包括对WebJars的支持。
    3. 自动注册Converter,GenericConverter,Formatter beans。
    4. 对HttpMessageConverters的支持。
    5. 自动注册MessageCodeResolver。
    6. 对静态index.html的支持。
    7. 对自定义Favicon的支持。
    8. 主动使用ConfigurableWebBindingInitializer bean

    三.模板引擎的选择

    FreeMarker<br>
    Thymeleaf<br>
    Velocity (1.4版本之后弃用,Spring Framework 4.3版本之后弃用)<br>
    Groovy<br>
    Mustache<br>
    

    注:jsp应该尽量避免使用,原因如下:

    1. jsp只能打包为:war格式,不支持jar格式,只能在标准的容器里面跑(tomcat,jetty都可以)
    2. 内嵌的Jetty目前不支持JSPs
    3. Undertow不支持jsps
    4. jsp自定义错误页面不能覆盖spring boot 默认的错误页面

    FreeMarker模板引擎

    • jar包依赖

        <dependency>
        		<groupId>org.springframework.boot</groupId>
        		<artifactId>spring-boot-starter-freemarker</artifactId>
        	</dependency>
        	
        	<!-- 对jquery的依赖-->
        	<dependency>
        		<groupId>org.webjars</groupId>
        		<artifactId>jquery</artifactId>
        		<version>2.1.4</version>
        </dependency>
      
    • 静态文件依赖

      springboot自动加载static目录下的静态文件

    • 静态页面文件格式

      index.ftl

        	<!DOCTYPE html>
        	<html>
        	<head>
        	<meta charset="UTF-8">
        	<title>Insert title here</title>
        	<link rel="stylesheet" type="text/css" href="/css/index/index.css" />
        	<link rel="shortcut icon" href="/images/favicon.ico">
        	<script type="text/javascript" src="/webjars/jquery/2.1.4/jquery.js"></script>
        	<script type="text/javascript">
        		$(function(){
        			$("p").click(function(){
        				alert("点击了");
        			})
        		})
        		
        	</script>
        	</head>
        	<body>
        		<img src="/images/photo111.png">
        		<p id="name">${name}</p>
        	</body>
        	</html>
      

    Thymeleaf模板引擎

    • jar包依赖

        <dependency>
        	<groupId>org.springframework.boot</groupId>
        	<artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
      
    • 文件格式

      index.html

        <!DOCTYPE html>
        <html xmlns="http://www.w3.org/1999/xhtml"
              xmlns:th="http://www.thymeleaf.org">
        	<head>
        		<meta charset="UTF-8">
        		<title>Insert title here</title>
        		<link rel="stylesheet" type="text/css" href="/css/index/index.css" />
        		<link rel="shortcut icon" href="/images/favicon.ico">
        		<script type="text/javascript" src="/webjars/jquery/2.1.4/jquery.js"></script>
        		<script type="text/javascript">
        			$(function(){
        				$("p").click(function(){
        					alert("点击了");
        				})
        			})
        			
        		</script>
        	</head>
        	<body>
        		<img src="/images/photo111.png">
        		<p id="name" th:text="${name}"></p>
        	</body>
        </html>
      

      在html标签里加上thymeleaf的约束:

      xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"

    jsp模板引擎

    • jar包依赖

        <dependency>
        	<groupId>org.apache.tomcat.embed</groupId>
        	<artifactId>tomcat-embed-jasper</artifactId>
        	<scope>provided</scope>
        </dependency>
        <dependency>
        	<groupId>javax.servlet</groupId>
        	<artifactId>jstl</artifactId>
        </dependency>
      
    • 打包格式必须为war包

    • 工程结构

    • 配置文件添加参数

      • spring.mvc.view.prefix=/WEB-INF/index/
      • spring.mvc.view.suffix=.jsp

    异常处理

    springboot项目运行过程中出现异常,springboot默认将异常信息处理交由BasicErrorController处理,映射路径为error

    • Spring Boot 将所有的错误默认映射到/error, 实现ErrorController

      自定义一个异常控制类,覆盖原来的,可以根据请求类型将异常处理分发到不同的处理方法中进行处理。可以同时实现返回错误页面,也可以返回json数据

        /**
         * 实现ErrorController接口,覆盖掉springboot默认的/error请求路径
         * @author sxq
         * @time 2018年6月6日 上午10:58:30
         *
         */
        @Controller
        @RequestMapping("error")
        public class MyErrorController implements ErrorController {
        
        	
        	@Autowired
            private ErrorAttributes errorAttributes;
        	
        	@Override
        	public String getErrorPath() {
        		return "/error";
        	}
        	
        	
        	/**
        	 * 	如果是页面请求,则进入该方法中,返回页面
        	 *	@param request
        	 *	@return
        	 *	Map<String,Object>
        	 */
        	@RequestMapping(produces=MediaType.TEXT_HTML_VALUE)
        	public String error(HttpServletRequest request){
        		Map<String, Object> map = getErrorAttributes(request, false);
        		Integer status = (Integer) map.get("status");
        		if(404==status){
        			return "error/404";
        		}else if(500==status){
        			return "error/500";
        		}
        		return "error/other";
        		
        //		
        	}
        	
        	/**
        	 * 	如果json请求,进入该方法中,返回json数据
        	 *	@param request
        	 *	@return
        	 *	String
        	 */
        	@RequestMapping(produces=MediaType.APPLICATION_JSON_VALUE)
        	@ResponseBody
        	public Map<?, ?> error1(HttpServletRequest request){
        		Map<String, Object> map = new HashMap<String, Object>();
        		//自定义异常类,获取异常信息
        		Throwable throwable= getThrowable(request);
        		if(throwable instanceof MyException){
        			MyException exception = (MyException) throwable;
        			map.put("code", exception.getCode());
        			map.put("message", exception.getMessage());
        		}else{
        			map.put("code", "999");
        			map.put("message", "未知错误");
        		}
        		return map;
        	}
        
        	/**
        	 * 	获取异常信息集合
        	 *	@param request
        	 *	@param includeStackTrace 是否获取栈信息,即报错的位置
        	 *	@return
        	 *	Map<String,Object>
        	 */
           private Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
        	   WebRequest webRequest = new ServletWebRequest(request);
                return errorAttributes.getErrorAttributes(webRequest, includeStackTrace);
            }
           
           
           /**
            * 	获取异常类
            *	@param request
            *	@return
            *	Throwable
            */
           private Throwable getThrowable(HttpServletRequest request){
        	   WebRequest webRequest = new ServletWebRequest(request);
        	   return errorAttributes.getError(webRequest);
           }
        
        
        }
      

      `

    • 添加自定义错误页面

      1. html静态页面

        可以在resources/templates/error目录下定义,也可以在/resources/public/error定义,前者的优先级高于后者

      1. 模板引擎下配置

        可以在resources/templates/error目录下定义,也可以在/resources/public/error定义,前者的优先级高于后者
        .html结尾的文件可以放在/resources/public/error目录下,但.ftl结尾的文件只能放在resources/templates/error目录下

    • 使用@ControllerAdvice注解处理异常

        @ControllerAdvice
        public class MyExceptionHandler {
        	
        	/**
        	 * 运行时异常
        	 *	@param exception
        	 *	@return
        	 *	ModelAndView
        	 */
        	@ExceptionHandler({ RuntimeException.class })
        	@ResponseStatus(HttpStatus.OK)
        	public ModelAndView processException(RuntimeException exception) {
        		System.out.println("进来了");
        		ModelAndView m = new ModelAndView();
        		m.addObject("roncooException", exception.getMessage());
        		m.setViewName("error/500");
        		return m;
        	}
        	
        	/**
        	 * 定义全局异常
        	 *	@param exception
        	 *	@return
        	 *	ModelAndView
        	 */
        	@ExceptionHandler({ Exception.class })
        	@ResponseStatus(HttpStatus.OK)
        	public ModelAndView processException(Exception exception) {
        		ModelAndView m = new ModelAndView();
        		m.addObject("roncooException", exception.getMessage());
        		m.setViewName("error/500");
        		return m;
        	}
        
        }
      

      找/thymeleaf/src/main/resources/templates/error目录下的错误页面

    springboot 自定义过滤器,监听器,servlet

    第一种方式:使用@ServletComponentScan注解

    @SpringBootApplication(scanBasePackages={"com.example.controller","com.example.exception","com.example.config"})
    @ServletComponentScan(basePackages={"com.example.filter","com.example.listener"})
    public class ThymeleafApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(ThymeleafApplication.class, args);
    	}
    }
    

    在ThymeleafApplication上加上ServletComponentScan注解

    • 自定义过滤器
      使用注解@WebFilter(urlPatterns="/"),urlPatterns="/"拦截所以请求

        @WebFilter(urlPatterns="/*")
        public class MyFilter implements Filter {
        
        	private static final LoggerUtil<MyFilter> logger = LoggerUtil.getInstance(MyFilter.class);
        	
        	@Override
        	public void init(FilterConfig filterConfig) throws ServletException {
        		logger.info("【MyFilter初始化了】");
        	}
        
        	@Override
        	public void doFilter(ServletRequest request, ServletResponse response,
        			FilterChain chain) throws IOException, ServletException {
        		HttpServletRequest req = (HttpServletRequest) request;
        		String url = req.getRequestURL().toString();
        		String uri = req.getRequestURI();
        		logger.info("【url】----{0}",url);
        		logger.info("【uri】----{0}",uri);
        		chain.doFilter(request, response);
        	}
        
        	@Override
        	public void destroy() {
        		logger.info("【MyFilter销毁了】");
        	}
      
        }
      
    • 自定义监听器

      使用注解@WebListener

        /**
         * 项目启动的时候,先启动ServletContextListener
         * @author sxq
         * @time 2018年6月7日 下午5:54:55
         *
         */
        @WebListener
        public class MyListener implements ServletContextListener{
        
        	private static final LoggerUtil<MyListener> logger = LoggerUtil.getInstance(MyListener.class);
        	@Override
        	public void contextInitialized(ServletContextEvent sce) {
        		
        		logger.info("初始化servlet上下文");
        	}
        
        	@Override
        	public void contextDestroyed(ServletContextEvent sce) {
        		
        	}
        
        }
      
    • 自定义servlet

      使用注解@WebServlet(urlPatterns="/print.do"),url路径前必须加上"/"

        @WebServlet(urlPatterns="/print.do")
        public class MyServlet extends HttpServlet {
        
        	/**
        	 * serialVersionUID
        	 */
        	private static final long serialVersionUID = 1L;
        	
        	private static final LoggerUtil<MyServlet> logger = LoggerUtil.getInstance(MyServlet.class);
        
        	@Override
        	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        			throws ServletException, IOException {
        		Map<String, Object> map = new HashMap<String, Object>();
        		map.put("timestamp", System.currentTimeMillis());
        		map.put("status", "OK");
        		resp.getWriter().write(JSONObject.toJSONString(map, true));
        	}
        
        	@Override
        	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        			throws ServletException, IOException {
        		super.doPost(req, resp);
        	}
        
        	@Override
        	public void destroy() {
        		logger.info("MyServlet销毁了。。。。。。。。");
        		super.destroy();
        	}
        
        	@Override
        	public void init(ServletConfig config) throws ServletException {
        		logger.info("MyServlet初始化了。。。。。。。。");
        		super.init(config);
        	}
        }
      

    第二种方式:通过注册 ServletRegistrationBean、 FilterRegistrationBean 和 ServletListenerRegistrationBean 获得控制

    • 创建MyServlet extends HttpServlet、MyFilter implements Filter、MyListener implements ServletContextListener

    • 在启动类中,使用@Bean注解,注册 ServletRegistrationBean、 FilterRegistrationBean 和 ServletListenerRegistrationBean,从而实现自定义Filter、servlet、listener

        @SpringBootApplication(scanBasePackages={"com.example.controller","com.example.exception","com.example.config"})
        @ServletComponentScan(basePackages={"com.example.filter","com.example.listener","com.example.servlet"})
        public class ThymeleafApplication {
        
        	public static void main(String[] args) {
        		SpringApplication.run(ThymeleafApplication.class, args);
        	}
        	
        	/**
        	 * 注册ServletRegistrationBean
        	 *	@return
        	 *	ServletRegistrationBean<MyServlet>
        	 */
        	 @Bean 
        	 public ServletRegistrationBean<MyServlet> servletRegistrationBean() { 
        	  return new ServletRegistrationBean<MyServlet>(new MyServlet(), "/print.do"); 
        	 } 
        	
        	 /**
        	  * 注册FilterRegistrationBean
        	  *	@return
        	  *	FilterRegistrationBean<MyFilter>
        	  */
        	 @Bean 
        	 public FilterRegistrationBean<MyFilter> filterRegistrationBean() { 
        	  return new FilterRegistrationBean<MyFilter>(new MyFilter(), servletRegistrationBean()); 
        	 } 
        	 
        	 /**
        	  * 注册ServletListenerRegistrationBean
        	  *	@return
        	  *	ServletListenerRegistrationBean<MyListener>
        	  */
        	 @Bean
        	 public ServletListenerRegistrationBean<MyListener> servletListenerRegistrationBean(){
        		 
        		 return new ServletListenerRegistrationBean<MyListener>(new MyListener());
        	 }
        	 
        }
      

    启动类实现ServletContextInitializer接口,直接完成注册。

    @SpringBootApplication(scanBasePackages={"com.example.controller","com.example.exception","com.example.config"})
    @ServletComponentScan(basePackages={"com.example.filter","com.example.listener","com.example.servlet"})
    public class ThymeleafApplication implements ServletContextInitializer{
    
    	public static void main(String[] args) {
    		SpringApplication.run(ThymeleafApplication.class, args);
    	}
    
    	@Override
    	public void onStartup(ServletContext servletContext)
    			throws ServletException {
    		servletContext.addFilter("myFilter", new MyFilter()).addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
    		servletContext.addServlet("myServlet", new MyServlet()).addMapping("/print.do");
    		servletContext.addListener(new MyListener());
    	}
    }
    

    添加拦截器

    • 自定义拦截器,继承HandlerInterceptorAdapter

        public class Intercepter extends HandlerInterceptorAdapter {
        
        	private static final LoggerUtil<Intercepter> logger = LoggerUtil.getInstance(Intercepter.class);
        	@Override
        	public boolean preHandle(HttpServletRequest request,
        			HttpServletResponse response, Object handler) throws Exception {
        		logger.info("进入前置处理方法!");
        		return super.preHandle(request, response, handler);
        	}
        
        	@Override
        	public void postHandle(HttpServletRequest request,
        			HttpServletResponse response, Object handler,
        			ModelAndView modelAndView) throws Exception {
        		logger.info("进入后置处理方法");
        		super.postHandle(request, response, handler, modelAndView);
        	}
        
        	@Override
        	public void afterCompletion(HttpServletRequest request,
        			HttpServletResponse response, Object handler, Exception ex)
        			throws Exception {
        		// TODO Auto-generated method stub
        		super.afterCompletion(request, response, handler, ex);
        	}
        
        	@Override
        	public void afterConcurrentHandlingStarted(HttpServletRequest request,
        			HttpServletResponse response, Object handler) throws Exception {
        		super.afterConcurrentHandlingStarted(request, response, handler);
        	}
        
        }
      
    • 自定义mvc配置类,继承DelegatingWebMvcConfiguration,重写addInterceptors方法

        /**
         * WebMvcConfigurer配置类
         * @author sxq
         * @time 2018年6月7日 下午6:15:32
         *
         */
        @Configuration
        public class MvcConfig extends DelegatingWebMvcConfiguration{
        	
        	private static final LoggerUtil<MvcConfig> logger = LoggerUtil.getInstance(MvcConfig.class);
        
        	/**
        	 * addResourceHandler----资源处理器需要拦截哪些静态资源请求。
        	 * addResourceLocations-----静态资源的位置
        	 */
        	@Override
        	protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        		registry.addResourceHandler(new String[]{"/images/**/*","/static/**/*","/templates/**/*"})
        			.addResourceLocations("classpath:/images/","classpath:/static/","/templates/");
        		super.addResourceHandlers(registry);
        	}
        	
        	/**
        	 * addViewController---设置请求url
        	 * setViewName----设置返回视图名称
        	 */
        	@Override
        	protected void addViewControllers(ViewControllerRegistry registry) {
        		registry.addViewController("/toLogin").setViewName("index/index");
        		super.addViewControllers(registry);
        	}
        	
        	/**
        	 * addInterceptor---设置拦截器的实例
        	 * addPathPatterns---设置拦截器拦截的url
        	 */
        	@Override
        	protected void addInterceptors(InterceptorRegistry registry) {
        		logger.info("进入添加拦截器方法上了!");
        		registry.addInterceptor(new Intercepter()).addPathPatterns("/**/*.do");
        		super.addInterceptors(registry);
        	}
        	
        }
      

    注意,在启动类中,扫描该配置类所在的包,使得@configuration注解生效

    springboot解决CORS(Cross-Origin Resource Sharing, 跨源资源共享)

    1. 使用场景

      浏览器默认不允许跨域访问,包括我们平时ajax也是限制跨域访问

      产生跨域访问的情况主要是请求的发起者与请求的接受者的域名不同,端口不同

    2. 解决方案

      通过设置Access-Control-Allow-Origin来实现跨域访问

    3. CORS与jsonp相比的优点

      1)JSONP 只能实现 GET 请求,而 CORS 支持所有类型的 HTTP 请求。

      2)使用 CORS,开发者可以使用普通的 XMLHttpRequest 发起请求和获得数据,比起 JSONP 有更好的
      错误处理。

      3)JSONP 主要被老的浏览器支持,它们往往不支持 CORS,而绝大多数现代浏览器都已经支持了 CORS

      浏览器支持情况

       	Chrome 3+ 
       	Firefox 3.5+ 
       	Opera 12+
       	Safari 4+
       	Internet Explorer 8+
      
    4. springboot 基于jsonp解决跨域问题

      服务端实现:

       @Controller
       public class JsonpController {
       
       	@RequestMapping("/jsonp.do")
       	@ResponseBody
       	public void jsonp(HttpServletResponse response,@RequestParam String callback){
       //		response.setContentType("text/html");
       		response.setCharacterEncoding("utf-8");
       		Map<String, Object> map = new HashMap<String, Object>();
       		map.put("name", "张三");
       		map.put("type", "jsonp");
       		try {
       			response.getWriter().write(callback+"("+JSONObject.toJSONString(map)+")");
       		} catch (IOException e) {
       			e.printStackTrace();
       		}
       	}
       }
      

      前端js实现:

       $("#jsonp").click(function(){
       	var data = {};
       	$.ajax({
       		type:"get",
       		url:"http://localhost:9080/jsonp.do",
       		data:data,
       		dataType: "jsonp",
       		jsonp:"callback",
       		//jsonpCallback:callback,
       		success:function(data){
       			$("#div").html(JSON.stringify(data));
       		}
       	})
      
       });
      

      jsonp:在一个jsonp请求中重写回调函数的名字。这个值用来替代在"callback=?"这种GET或POST请求中URL参数里的"callback"部分,比如{jsonp:'onJsonPLoad'}会导致将"onJsonPLoad=?"传给服务器。

      jsonpCallback:为jsonp请求指定一个回调函数名。这个值将用来取代jQuery自动生成的随机函数名。这主要用来让jQuery生成度独特的函数名,这样管理请求更容易,也能方便地提供回调函数和错误处理。你也可以在想让浏览器缓存GET请求的时候,指定这个回调函数名。

    5. 具体实现

      • 全局配置

        【1】继承DelegatingWebMvcConfiguration,重写addCorsMappings(CorsRegistry registry)方法

        设置请求url映射、设置请求允许来源,允许访问的客户端地址、允许访问请求方法,如GET、POST

          @Configuration
          public class MvcConfig extends DelegatingWebMvcConfiguration {
          
          	@Override
          	protected void addCorsMappings(CorsRegistry registry) {
          		/**
          		 * addMapping----设置请求url映射
          		 * allowedOrigins ----设置请求允许来源,设置客户端地址
          		 * allowedMethods -----允许访问请求方法,如GET、POST
          		 */
          		registry.addMapping("/cors/**").allowedOrigins("http://localhost:8090")
          		.allowedMethods("GET");
          		super.addCorsMappings(registry);
          	}
          
          }
        

        【2】定义方法

          @RestController
          @RequestMapping("/cors")
          public class CorsController extends BaseController{
          
          	
          	@RequestMapping("/get.do")
          	public Map<String, Object> get(){
          		Map<String, Object> map = new HashMap<String, Object>();
          		map.put("name", "张三");
          		map.put("sex", "男");
          		logger.debug("跨域返回值{0}", map);
          		return map;
          	}
          }
        

        【3】测试js代码示例如下

          $("p").click(function(){
          	$.ajax({
          		type:"GET",
          		url:"http://localhost:9080/cors/get.do",
          		success:function(data){
          			$("#div").html(JSON.stringify(data));
          		},
          		
          		error:function(data){
          			$("#div").html(JSON.stringify(data.responseJSON));
          		}
          	});
          })
        
      • 细粒度设置 在方法上使用@CrossOrigin注解

        【1】定义方法

          @RestController
          @RequestMapping("/annoCors")
          public class AnnoCorsController extends BaseController{
          
          	@RequestMapping("test")
          	@CrossOrigin(origins="http://localhost:8090")
          	public Map<String, Object> cors(){
          		Map<String, Object> map = new HashMap<String, Object>();
          		map.put("name", "张三");
          		map.put("type", "注解");
          		logger.debug("基于注解的跨域返回值{0}", map);
          		return map;
          	}
          }
        

    springboot 文件上传

    springboot文件与springmvc文件上传差不多
    
    • 单个文件上传

      • 前端实现

          <form action="file/upload" enctype="multipart/form-data" method="post">
          	<input type="file" name="file" />
          	<input type="submit" value="上传单个文件"/>
          </form>
        
      • 服务端实现

          @RequestMapping("file/upload")
          public String upload(HttpServletRequest request, @RequestParam MultipartFile file){
          	File parent = new File("C:\Users\admin\Desktop");
          	if(!parent.exists()){
          		parent.mkdirs();
          	}
          	File dir = new File(parent,"b.png");
          	try {
          		file.transferTo(dir);
          	} catch (IllegalStateException e) {
          		request.setAttribute("MSG", "文件上传失败");
          		e.printStackTrace();
          	} catch (IOException e) {
          		request.setAttribute("MSG", "文件上传失败");
          		e.printStackTrace();
          	}
          	
          	request.setAttribute("MSG", "文件上传成功");
          	return "success";
          }
        
    • 批量文件上传

      • 前端实现

          <div class="div">
          	<form action="uploads" enctype="multipart/form-data" method="post">
          		<input type="file" name="file" /><br>
          		<input type="file" name="file" /><br>
          		<input type="file" name="file" /><br>
          		<input type="submit" value="上传多个文件"/>
          	</form>
          </div>
        
      • 服务端实现

          @RequestMapping("uploads")
          public @ResponseBody String uploads(MultipartHttpServletRequest request){
          	List<MultipartFile> files = request.getFiles("file");
          	if(files==null||files.size()==0){
          		return "上传文件不能为空!";
          	}
          	String filePath = request.getSession().getServletContext().getRealPath("/upload");
          	File file = new File(filePath);
          	if(!file.exists()){
          		file.mkdirs();
          	}
          	boolean flag = true;
          	for(MultipartFile multipartFile:files){
          		String fileName = multipartFile.getOriginalFilename();
          		long size = multipartFile.getSize();
          		if(size==0){
          			flag = false;
          			continue;
          		}
          		flag = true;
          		try {
          			multipartFile.transferTo(new File(file, fileName));
          		} catch (IllegalStateException | IOException e) {
          			e.printStackTrace();
          			return "文件上传失败|"+e.getMessage();
          		}
          	}
          	
          	if(!flag){
          		return "上传文件不能为空!";
          	}
          	
          	return "上传成功";
          }
        
    • 配置文件配置参数

      1、spring.http.multipart.maxFileSize=1Mb 上传文件大小

      2、spring.http.multipart.maxRequestSize=100Mb

      3、spring.http.multipart.enabled=true #默认支持文件上传.

      4、spring.http.multipart.file-size-threshold=0 #支持文件写入磁盘.

      5、spring.http.multipart.location= # 上传文件的临时目录

    springboot基于关系型数据库实现

    spring-jdbc

    springboot默认使用的数据源是org.apache.tomcat.jdbc.pool.DataSource

    DataSourceConfiguration类中,使用@Bean注解,创建了org.apache.tomcat.jdbc.pool.DataSource实例,参考代码如下:

    /**
     * Tomcat Pool DataSource configuration.
     */
    @ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)
    static class Tomcat extends DataSourceConfiguration {
    
    	@Bean
    	@ConfigurationProperties(prefix = "spring.datasource.tomcat")
    	public org.apache.tomcat.jdbc.pool.DataSource dataSource(
    			DataSourceProperties properties) {
    		org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(
    				properties, org.apache.tomcat.jdbc.pool.DataSource.class);
    		DatabaseDriver databaseDriver = DatabaseDriver
    				.fromJdbcUrl(properties.determineUrl());
    		String validationQuery = databaseDriver.getValidationQuery();
    		if (validationQuery != null) {
    			dataSource.setTestOnBorrow(true);
    			dataSource.setValidationQuery(validationQuery);
    		}
    		return dataSource;
    	}
    
    }
    

    知识点:

    1. @Bean 的用法

    @Bean注解是一个方法级别上的注解,主要用在@configuration注解的类里,也可以用在@Component注解的类里,添加bean的id为方法名。

    2. 例子

    下面是@Configuration里的一个例子

    	@Configuration
    	public class AppConfig {
    	
    	    @Bean
    	    public TransferService transferService() {
    	        return new TransferServiceImpl();
    	    }
    	
    	}
    

    等价于xml里的配置

    	<beans>
        	<bean id="transferService" class="com.acme.TransferServiceImpl"/>
    	</beans>
    

    pom文件引用jar包

    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-jdbc</artifactId>
    	</dependency>
    	<dependency>
    		<groupId>mysql</groupId>
    		<artifactId>mysql-connector-java</artifactId>
    		<scope>runtime</scope>
    	</dependency>
    

    配置文件

    spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&ampcharacterEncoding=UTF-8&ampautoReconnect=true
    						&ampfailOverReadOnly=false 
    spring.datasource.username=root
    spring.datasource.password=123456
    

    更多配置信息参考JdbcProperties

    持久层实现

    @Repository
    public class UserDaoImpl implements UserDao {
    
    	@Autowired
    	private JdbcTemplate template;
    
    	
    	/**
    	 * 新增记录
    	 */
    	@Override
    	public int addUser(User user) {
    		String sql = "insert into user (name,create_time) values(?,?)";
    		return template.update(sql, user.getName(),user.getCreateTime());
    	}
    
    	
    	/**
    	 * 根据id删除记录
    	 */
    	@Override
    	public int delUserById(int id) {
    		String sql = "delete from user where id=?";
    		
    		return template.update(sql, id);
    	}
    	
    	/**
    	 * 以实体类形式,返回单条记录
    	 */
    	@Override
    	public User queryUser(User user) {
    		String sql = "select * from user where id=?";
    		return (User) template.query(sql, new MyRowMapper(User.class), user.getId()).get(0);
    	}
    }
    

    springboot自动在容器中创建JdbcTemplate实例。在JdbcTemplateAutoConfiguration类中创建的
    代码如下:

    @Bean
    @Primary
    @ConditionalOnMissingBean(JdbcOperations.class)
    public JdbcTemplate jdbcTemplate() {
    	JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSource);
    	JdbcProperties.Template template = this.properties.getTemplate();
    	jdbcTemplate.setFetchSize(template.getFetchSize());
    	jdbcTemplate.setMaxRows(template.getMaxRows());
    	if (template.getQueryTimeout() != null) {
    		jdbcTemplate
    				.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
    	}
    	return jdbcTemplate;
    }
    

    java.sql.ResultSetMetaData类详解

    An object that can be used to get information about the types and properties of the columns in a ResultSet object. 
    The following code fragment creates the ResultSet object rs, creates the ResultSetMetaData object rsmd, and uses rsmd to 
    find out how many columns rs has and whether the first column in rs can be used in a WHERE clause. 
    
    
     ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");
     ResultSetMetaData rsmd = rs.getMetaData();
     int numberOfColumns = rsmd.getColumnCount();
     boolean b = rsmd.isSearchable(1);
    

    ResultSetMetaData是一个借助ResultSet对象,获取字段的类型和属性信息

    spring-data-jpa

    • 什么是jpa

      jpa的全称是java Persistence API(java持久化API),可以通过注解或xml来描述实体对象与关系表之间的映射关系。将实体对象持久化到数据库中。

    • 什么是spring-data-jpa

      spring-data-jpa是spring提供的一套简化jpa开发的框架 ,按照约定好的【方法命名规则】写dao层接口,就可以在不写接口实现的情况下操作数据库,同时提供了除了crud之外的很多功能。如分页,排序。
      底层还是依赖Hibernate的JPA技术实现

    • spring-data-jpa的好处?

      开发人员只需操作实体对象,不用关注sql如何实现

    • springboot集成spring-data-jpa

      1. 导入maven坐标

         <dependency>
         	<groupId>org.springframework.boot</groupId>
         	<artifactId>spring-boot-starter-data-jpa</artifactId>
         </dependency>
        
      2. 配置文件配置jpa信息

         //表不存在,自动创建
         spring.jpa.hibernate.ddl-auto= update 
         //显示 sql 语句 
         spring.jpa.show-sql=true
        
      3. 基于jpa,实现对数据库访问demo

        • 配置文件配置参数

            spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&ampcharacterEncoding=UTF-8
            &ampautoReconnect=true&ampfailOverReadOnly=false 
            spring.datasource.username=root
            spring.datasource.password=123456
            
            //表不存在,自动创建
            spring.jpa.hibernate.ddl-auto= update 
            //显示 sql 语句 
            spring.jpa.show-sql=true
          

          参考JpaProperties

        • 创建实体类,使用jpa注解,实现实体类与关系表之间的映射

            @Entity(name="student")
            public class Student {
            
            	@Id
            	@GeneratedValue(strategy=GenerationType.AUTO)
            	private int stuId;
            	
            	@Column(length=5,nullable=true)
            	private String stuName;
            	
            	@Column(length=20)
            	private String stuNo;
            
            	public int getStuId() {
            		return stuId;
            	}
            
            	//setter和getter方法省略
          
            }
          
        • 编写dao层接口,继承PagingAndSortingRepository

            public interface StudentRepository extends PagingAndSortingRepository<Student, Integer> {
            	Student findStuByStuId(int id);
            	List<Student> findStuByStuNameLike(String name);
            	List<Student> findStuByStuIdBetween(int beginId,int endId);
            }
          

          基于注解查询语句

            @Query(value="select s from student s where s.stuNo=?1")
            Student findStuByStuNo(String stuNo);
          

          1、表名为@Entity(name="student")的name属性值

          2、必须将所有字段全部查回来,否则无法转换成实体类

          3、查询条件的字段为实体类的属性
          4、注解优先级高于方法命名规则

        • 测试

            	@Autowired
            	private StudentRepository repository;
            	
            	private LoggerUtil logger = LoggerUtil.getInstance(getClass());
            	@Test
            	public void insertStu(){
            		Student entity = new Student("李打野", "2012080244");
            		repository.save(entity);
            	} 
            	
            	@Test
            	public void qryStuById(){
            		Student student = repository.findStuByStuId(1);
            		logger.debug("id为1的学生新信息为{0}",student.toString());
            	}
            	
            	@Test
            	public void pageQry(){
            		@SuppressWarnings("deprecation")
            		Page<Student> page = repository.findAll(new PageRequest(0, 10,new Sort(Direction.DESC, "stuNo")));
            		
            		logger.debug("分页查询结果===={0}",page.getContent());
            	}
            	
            	@Test
            	public void findStuByStuNameLike(){
            		List<Student> list = repository.findStuByStuNameLike("李%");
            		
            		logger.debug("根据姓名模糊查询的结果为{0}",list);
            	}
            	@Test
            	public void findStuByStuIdBetween(){
            		List<Student> list = repository.findStuByStuIdBetween(1,1);
            		
            		logger.debug("根据id范围查询的结果为{0}",list);
            	}
          
        • spring-data-jpa dao层接口继承层级如图所示

        • spring-data-jpa关键字

          查询关键字
          序号 逻辑关键字 关键字表达
  • 相关阅读:
    vue nextTick使用
    Vue slot插槽内容分发
    vue 项目设置实现通过本地手机访问
    vue router mode模式在webpack 打包上线问题
    html设置 hight100%问题
    更新模块通知栏显看不到当前进度,以及更新下载中可以清理通知问题,华为强制更新退出软件后台下载不显示通知问题
    ScrollView下嵌套GridView或ListView默认不在顶部的解决方法
    文件说明注释
    EditText双光标问题
    原 android重启应用(应用重新启动自身)
  • 原文地址:https://www.cnblogs.com/sxqjava/p/10409323.html
Copyright © 2020-2023  润新知