Spring Boot、SpringCloud框架

SpringBoot

第二章、Spring Boot环境搭建

一、Spring Boot搭建
1.创建Maven Project添加boot开发包

pom.xml添加下面定义

<!-- spring boot基础包 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.2.RELEASE</version> <!--版本太低可能会报错-->
 </parent>

<dependencies>
    <!-- boot核心包,包含自动配置,ioc,yaml解析 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
        <!-- mvc、rest -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
2.添加boot配置文件(application.properties或application.yml)

在项目名中配置

application.properties文件中
spring.datasource.name=scott
spring.datasource.password=12345
application.yml文件中
spring:
 datasource:
  name: scott
  password: 12345
案例:application.properties中的代码
server.port=8080
server.context-path=/boot01
3.主启动类
	@SpringBootApplication
	public class MyBootApplication {
	    public static void main(String[] args){
	        SpringApplication.run(MyBootApplication.class, args);
	    }
	}
4.编写Controller
	@RestController //默认返回JSON格式 可以替换成@Controller和@ResponseBody
	public class HelloController {
	
	    @RequestMapping("/hello/{name}")
	    public String say(@PathVariable("name")String name){
	        return "Hello World "+name;
	    }
	
	}
	或
    @Controller
	public class HelloController {
	
	    @RequestMapping("/hello/{name}")
	    @ResponseBody// @ResponseBody注解的作用就是把控制视图方法返回的内容返回到请求页面上
	    public String say(@PathVariable("name")String name){
	        return "Hello World "+name;
	    }
	
	}
5.运行MyBootApplication主启动类,启动boot内置的tomcat

打开浏览器输入:http://localhost:8888/boot01/hello/scott

二、SpringBoot Beans管理和自动配置
1.@SpringBootApplication
  • 该标记大小写敏感,是由若干个标记合成,包含Bean定义、组件扫描、自动配置等功能。主要包含以下标记
    • @SpringBootConfiguration–>@Configuration–>@Component
    • @ComponentScan
    • @EnableAutoConfiguration
    标注信息.png-48.6kB

1.1 @Configuration+@Bean

作用:可以将程序中的Bean对象放入Spring容器中。

类似于:xml文件中 
<beans>
    <bean id="" class="">
<beans>

一般会使用@Configuration+@Bean组合。不加@Bean会提示找不到类
注解标记使用格式:

package cn.xdl;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import cn.xdl.dao.UserDao;

@EnableAutoConfiguration//配置类 如果不加@Bean会报错
//@Configuration+Bean要一起使用 
public class DaoConfig {

    @Bean(name="userDao")//将返回的UserDao对象加入Spring容器,默认id是方法名
    public UserDao createUserDao(){
        return new JdbcUserDao();
    }

    @Bean(name="bookDao")
    public BookDao createBookDao(){
        return new JdbcBookDao();
    }

}

//接口和实现类
package cn.xdl.dao;

public interface BookDao {
	void load();
}

package cn.xdl.dao;

public class BookDaoImpl implements BookDao {
	@Override
	public void load() {
		System.out.println("load");
	}
}

创建SpringBoot的Spring容器:

public static void main(String[] args){
    ApplicationContext ac = 
        SpringApplication.run(DaoConfig.class, args);
    UserDao userDao = ac.getBean("userDao",UserDao.class);
    userDao.save();
    BookDao bookDao = ac.getBean("bookDao",BookDao.class);
    bookDao.load();
}

1.2 @Import @Scope(“prototype”)非单例

  • 提示:
    • @Bean默认是单例对象,可以使用@Scope(“prototype”)改变。
    • @Import标记可以引入其他@Configuration配置类
@Configuration//配置类
@Import(DataSourceConfig.class)//导入另一个配置类
//上面等于 @Import(value=cn.xdl.config.DataSourceConfig.class)
public class DaoConfig {
    //... ...
}
2.扫描@ComponentScan
  • 作用:开启组件扫描,等价于<context:component-scan base-package=“xx”/>配置。
    JAR包引用的类用@Configuration+@Bean 。自己写的类用@ComponentScan

提示:

  • @ComponentScan可以指定basePackage扫描路径;不指定默认扫描当前包和子包组件。
    使用提示:
  • jar包组件采用@Bean模式纳入Spring容器;自己编写的组件采用组件扫描@ComponentScan纳入Spring容器。
    项目代码包结构
    建议采用如下包结构组织代码
    1.png-24kB
    提示:@Configuration包含@Component标记,适用于组件扫描加载。
package cn.xdl.config;

import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import cn.xdl.service.UserService;

@ComponentScan(basePackages="cn.xdl.service")//扫描 cn.xdl.service包下的代码
//@ComponentScan //什么都不加默认扫描
public class ComponentScanConfig {

	public static void main(String[] args) {
		ConfigurableApplicationContext ac = SpringApplication.run(ComponentScanConfig.class, args);
		UserService bean = ac.getBean("UserService", UserService.class);
		bean.register();
	}
	
}

service组件 @Service

package cn.xdl.config.service;

import org.springframework.stereotype.Service;

@Service("userService") 等同于@Service(value="UserService")
public class UserServiceImpl implements UserService{

    @Override
    public void regist() {
        System.out.println("用户注册处理");
    }

}

创建SpringBoot的Spring容器:

ApplicationContext ac = 
        SpringApplication.run(ComponetScanConfig.class, args);
UserService service = 
    ac.getBean("userService",UserService.class);
service.regist();
3.@EnableAutoConfiguration
  • SpringBoot核心自动配置,启动自动配置后,Spring容器会自动去spring-boot-autoconfigure.jar,在它META-INF/spring.factories文件加载一系列功能的自动配置组件。例如DataSourceAutoConfiguration、JdbcTemplateAutoConfiguration、AopAutoConfiguration、WebMvcAutoConfiguration等功能。通过自动配置加载这些组件,创建功能相关的对象。
  • 如果不想加载某一个配置文件(比如org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration类文件)
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
4.@ConfigurationProperties
  • 参数注入:
  • 通过自动配置组件ConfigurationPropertiesAutoConfiguration支持@ConfigurationProperties标记。
    作用:将application.properties中的参数值注入到某个Bean对象中。

使用方法:

  • application.properties文件 名称不能随便改
#server
name=xielong #注意不要用username 否则跟系统用户变量有冲突
password=12345
server.port=8888
  • JAVA文件
@Component("dbparams")//扫描
@ConfigurationProperties//注入properties参数
public class DB {

    private String name;//自动注入name值  如果用${username}会取出系统账户报错
    //因为跟application.properties文件的参数一致 不需要转换

    @Value("${password}")
    private String pass;//注入password值
    //省略set和get方法   
} 
  • 提示:如果使用@ConfigurationProperties(prefix=“db”)会注入db.username值和db.password值。
  • 注意:@ConfigurationProperties需要@EnabledAutoConfiguration或@SpringBootApplication开启自动配置才能用。
#server application.properties文件
db.username=xielong
db.password=12345
server.port=8888

DB的JAVA文件


package cn.xdl.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component("dB")
@ConfigurationProperties(prefix="db")//注入参数前缀 不带'.' //@ConfigurationProperties(prefix="db.") 如果加了'.',取到的数据为空
public class DB {
	
	private String username;//不需要加"${username}" 会自动匹配 db.username
	private String password;//不需要加"${password}"
	
	public DB() {
		super();
	}
	public DB(String username, String password) {
	    ...
	}
	getter/setter;
	
}
@ComponentScan
@Configuration
@EnableAutoConfiguration
public class MyBootApplication {

    public static void main(String[] args){
        //@ComponentScan加载扫描配置
        ApplicationContext ac = 
            SpringApplication.run(MyBootApplication.class, args);
        //省略...
	    DB db = ac.getBean("dB", DB.class);
	    System.out.println(db.getUsername());
	    System.out.println(db.getPassword());
    }
}@SpringBootApplication//一个标记顶前面3个
public class MyBootApplication {

    public static void main(String[] args){
        //@ComponentScan加载扫描配置
        ApplicationContext ac = 
            SpringApplication.run(MyBootApplication.class, args);
        //省略...
	    DB db = ac.getBean("dB", DB.class);
	    System.out.println(db.getUser());
	    System.out.println(db.getName());
    }
}
使用JdbcTemplate:
直接注入就行 
三、SpringBoot连接池应用
1.默认自动配置
    1. SpringBoot可以通过自动配置创建出DataSource对象;程序员也可以手动创建。
      需要引入spring-boot-starter-jdbc数据库访问部分的jar包支持。
    1. 1.SpringBoot默认连接池
      SpringBoot可以默认创建连接池对象,创建出的对象id名为dataSource.创建机制如下:

    2. 优先创建tomcat-jdbc连接池对象。
      (需要引入spring-boot-starter-jdbc.jar包支持)

    3. 没有tomcat-jdbc,会创建HikariCP连接池对象
      (需要引入hikaricp.jar支持)

    4. 没有HikariCP,会创建dbcp连接池对象
      (需要引入dbcp.jar支持)

    5. 没有dbcp,会创建dbcp2连接池对象
      (需要引入dbcp2.jar支持)

  • SpringBoot默认连接池参数定义如下:

#application.properties
spring.datasource.username=xxx
spring.datasource.password=xxx
spring.datasource.url=xxx
spring.datasource.driver-class-name=xxx
  • 示例:application.properties文件名不能错
#default datasource
spring.datasource.username=system
spring.datasource.password=123456
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver

可以通过spring.datasource.type参数指定创建连接池对象类型。

2.多个数据源时,需要手动创建连接池 @Primary//默认

手动创建连接池代码:

@Configuration
public class DataSourceConfig {

    @Bean(name="dbcp2")
    @ConfigurationProperties(prefix="db.datasource2")
    public DataSource createDbcp2(){
//      BasicDataSource ds = new BasicDataSource();
//      return ds;
        DataSource ds = DataSourceBuilder.create()
                .type(BasicDataSource.class).build();
        return ds;
    }

    @Bean(name="dbcp1")
    @Primary//默认采用该连接池
    @ConfigurationProperties(prefix="db.datasource1")
    public DataSource createDbcp1(){
        DataSource ds = DataSourceBuilder.create()
                .type(BasicDataSource.class).build();
        return ds;
    }

}
  • 数据源连接参数定义:
#datasource1
db.datasource1.username=SCOTT
db.datasource1.password=TIGER
db.datasource1.url=jdbc:oracle:thin:@localhost:1521:XE
#datasource2
db.datasource2.username=SCOTT
db.datasource2.password=TIGER
db.datasource2.url=jdbc:oracle:thin:@localhost:1521:XE
db.datasource2.driverClassName=oracle.jdbc.OracleDriver
  • pom.xml文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>cn.xdl</groupId>
  <artifactId>boot-dao</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  
  <parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.4.7.RELEASE</version>
	<relativePath/>
  </parent>
  
  	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.7</java.version>
	</properties>
	
	<dependencies>
		<!-- bean扫描、自动配置、@bean定义 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		
		<!-- tomcat连接池 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
			<!-- 排除内部的tomcatjdbc -->
			<exclusions>
				<exclusion>
					<groupId>org.apache.tomcat</groupId>
					<artifactId>tomcat-jdbc</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		
		<!-- druid -->
		
		<!-- dbcp -->
		<!-- 
		<dependency>
			  <groupId>commons-dbcp</groupId>
			  <artifactId>commons-dbcp</artifactId>
		</dependency>
		 -->
		 
		<!-- dbcp2 -->
		<dependency>
		  <groupId>org.apache.commons</groupId>
		  <artifactId>commons-dbcp2</artifactId>
		</dependency>
		
		<!-- oracle驱动采用buildpath引入了 -->
		

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

</project>
  • 主启动类
@SpringBootApplication
public class MyBootApplication {

		public static void main(String[] args) throws SQLException {
			ApplicationContext ac = SpringApplication.run(MyBootApplication.class, args);
//			DataSource dataSource = ac.getBean("dataSource", DataSource.class);
//			System.out.println(dataSource.getConnection());
			
//			DataSource bean = ac.getBean("dbcp1", DataSource.class);
//			System.out.println(bean);
			
			DataSourceConfig bean = ac.getBean("dataSourceConfig", DataSourceConfig.class);
			DataSource createDbcp1 = bean.createDbcp1();
			System.out.println(createDbcp1.getConnection());
		}	
}
  • 注意:手动创建连接池对象后,Boot默认连接池不再创建。
四、SpringBoot和Mybatis整合结构

SpringBoot和Mybatis整合
示例代码:https://github.com/CNxielong/SpringBoot/boot-day03

1.采用注解定义SQL
  • 在Mapper接口中,使用@Select、@Insert、@Delete、@Update标记定义SQL语句。去除了XML定义SQL文件。

示例:DeptDao java文件

package cn.xdl.dao;

import java.util.List;
import org.apache.ibatis.annotations.Select;
import cn.xdl.entity.Dept;

public interface DeptDao {
	
	@Select("SELECT * FROM XDL_DEPT")
	List<Dept> queryAll();
}

2.分页功能

引入pagehelper-spring-boot-starter工具包,然后在代码中直接使用PageHelper.startPage()方法就可以。(boot内部采用自动配置引入PageHelper对象)

MyBootApplication主启动类JAVA文件

@SpringBootApplication
@MapperScan(basePackages = "cn.xdl.dao")
public class MyBootApplication {

	public static void main(String[] args) throws SQLException {
		ConfigurableApplicationContext ac = SpringApplication.run(MyBootApplication.class, args);
		DeptDao deptDao = ac.getBean("deptDao", DeptDao.class);
		PageHelper.startPage(1, 2);//顺序放在 结果集前面
		List<Dept> list = deptDao.queryAll();
		for (Iterator iterator = list.iterator(); iterator.hasNext();) {
			Dept dept = (Dept) iterator.next();
			System.out.println(dept);
		}
	}

}
		<!-- 分页插件 https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
		<dependency>
			<groupId>com.github.pagehelper</groupId>
			<artifactId>pagehelper-spring-boot-starter</artifactId>
			<version>1.2.3</version>
		</dependency>
3.SpringBoot和Spring MVC

主要:引入spring-boot-starter-web工具包,内部集成tomcat服务器、spring mvc开发包。

- 案例1:Hello World
- /hello.do-->DispatcherServlet-->HandlerMapping-->HelloController-->ModelAndView-->ViewResolver-->/hello.jsp
- 在boot中开发者只需要编写Controller和JSP,DispatcherServlet和HandlerMapping、ViewResolver都会采用自动配置。

1.在pom.xml中追加boot web和tomcat jasper两部分jar包

	<!-- mvc -->
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<!-- jsp解析器 -->
	<dependency>
	  <groupId>org.apache.tomcat.embed</groupId>
	  <artifactId>tomcat-embed-jasper</artifactId>
	</dependency>

2.在application.properties中定义server和viewresolver参数

	#server
	server.port=8888
	
	#viewresolver
	spring.mvc.view.prefix=/
	spring.mvc.view.suffix=.jsp

3.编写HelloController,使用@Controller和@RequestMapping标记

	@Controller
	public class HelloController {
	
	    @RequestMapping("/hello.do")
	    public ModelAndView say(){
	        ModelAndView mav = new ModelAndView();
	        mav.setViewName("hello");//hello.jsp视图名为hello
	        mav.getModel().put("msg", "Hello Spring Boot MVC");
	        return mav;
	    }
	
	}

4.在src/main/webapp编写hello.jsp

	<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
	<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
	<html>
	  <head>
	    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	    <title>Insert title here</title>
	  </head>
	  <body>
	    <h1>${msg}</h1>
	  </body>
	</html>

5.运行启动类MyBootAppliation测试

	@SpringBootApplication
	@MapperScan(basePackages={"cn.xdl.boot.dao"})//扫描加载mapper接口
	public class MyBootApplication {
	
	    public static void main(String[] args) {
	        //创建spring容器,启动tomcat服务器
	        SpringApplication.run(MyBootApplication.class, args);
	    }
	}

打开浏览器输入: http://localhost:8888/hello.do

- 案例2:列表显示 JSTL表达式

1.编写DeptController,注入DeptDao对象

	@Controller
	public class DeptController {
	
	    @Autowired
	    private DeptDao deptDao;
	
	    @RequestMapping("/dept/list.do")
	    public ModelAndView list(){
	        ModelAndView mav = new ModelAndView();
	        mav.setViewName("dept_list");//dept_list.jsp
	        List<Dept> list = deptDao.findAll();
	        mav.getModel().put("depts", list);
	        return mav;
	    }
	
	}

2.编写dept_list.jsp

	<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
	<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
	<html>
	<head>
	    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	    <title>Insert title here</title>
	</head>
	<body>
	    <h1>部门列表</h1>
	    ${depts}
	</body>
	</html>

3.在pom.xml中追加jstl开发包定义

	<!-- jstl -->
	<dependency>
	  <groupId>jstl</groupId>
	  <artifactId>jstl</artifactId>
	  <version>1.2</version>
	</dependency>

4.在dept_list.jsp添加taglib引入,使用jstl标签

	<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
	
	<table>
	    <c:forEach items="${depts}" var="dept">
	    <tr>
	        <td>${dept.deptno}</td>
	        <td>${dept.dname}</td>
	        <td>${dept.loc}</td>
	    </tr>
	    </c:forEach>
	</table>

5.启动MyBootApplication测试

- 案例3:列表删除

1.编写DeptController,添加delete方法

2.	@Controller
3.	@RequestMapping("/dept")//一下都是/dept下的“.do”
4.	public class DeptController {
5.	
6.	    @Autowired
7.	    private DeptDao deptDao;
8.	
9.	    @RequestMapping("/list.do")
10.	    public ModelAndView list(){
11.	        ModelAndView mav = new ModelAndView();
12.	        mav.setViewName("dept_list");//dept_list.jsp
13.	        List<Dept> list = deptDao.findAll();
14.	        mav.getModel().put("depts", list);
15.	        return mav;
16.	    }
17.	
18.	    @RequestMapping("/delete.do")
19.	    public String delete(@RequestParam("id") int deptno){
20.	        deptDao.delete(deptno);
21.	        return "redirect:/dept/list.do";
22.	    }
23.	
24.	}

	
	@Autowired
	DeptDao deptdao;

	@RequestMapping("/dept/list.do")
	public ModelAndView list(){
		ModelAndView mav = new ModelAndView();
		List<Dept> list = deptdao.queryAll();
		mav.setViewName("deptList");
		mav.getModel().put("deptList", list);
		return mav;
	}
	
	@RequestMapping("/dept/delete.do")//最简洁的写法
	public String deleteByDno(@RequestParam("dno") int dno){
		deptdao.deleteDept(dno);
		return "redirect:/dept/list.do";
	}
	
//	@RequestMapping("/dept/delete.do") //这种方式删除后展现为空结果的
//	public ModelAndView deleteByDno(@RequestParam("dno") int dno){
//		ModelAndView mav = new ModelAndView();
//		deptdao.deleteDept(dno);
//		mav.setViewName("deptList");
//		return mav;
//	}
	
//	@RequestMapping("/dept/delete.do") //这种方式删除后重定向
//	public ModelAndView deleteByDno(@RequestParam("dno") int dno){
//		ModelAndView mav = new ModelAndView();
//		deptdao.deleteDept(dno);
//		RedirectView view = new RedirectView("/dept/list.do");
//		mav.setView(view);
//		return mav;
//	}

2.编写dept_list.jsp追加删除按钮

	<table>
	    <c:forEach items="${depts}" var="dept">
	    <tr>
	        <td>${dept.deptno}</td>
	        <td>${dept.dname}</td>
	        <td>${dept.loc}</td>
	        <td>
	            <a href="delete.do?id=${dept.deptno}">删除</a>
	        </td>
	    </tr>
	    </c:forEach>
	</table>
4、Boot MVC异常处理

4.1全局处理(BasicErrorController 继承 ErrorController)

  • 1.原理
    • 启动Boot程序,自动配置组件ErrorMvcAutoConfiguration自动创建一个BasicErrorController对象,对象中提供了两个/error请求处理。
    • 当Controller组件抛出异常,Boot底层会自动转发一个/error请求,会调用BasicErrorController处理,输出一个Whitelabel Error Page错误页面。
 
  • 2.自定义一个ErrorController
    • 开发者自定义个ErrorController组件,提供/error处理方法。(自定义后,默认的BasicErrorController会失效)implements ErrorController
@Controller //不能丢 否则默认采取原先的BasicErrorController
public class MyErrorController implements ErrorController {

	@Override
	public String getErrorPath() {
		return "/error"; //这一行固定写法不能改
//		return "/exception";//如果用这一行 启动报错
	}
	
	@RequestMapping("/error")//跟上面对应
	public ModelAndView handlerException(){
		ModelAndView mav = new ModelAndView();
		mav.setViewName("exception");
		mav.getModel().put("msg", "这是自定义的异常");
		return mav;
	}

}

4.2局部(@ExceptionHandler)
可以在某个Controller组件内部定义异常处理方法


@Controller //局部异常处理
public class LocalException {
	
	@RequestMapping("/localException.do")
	public String local(){
		String[] s = null;
		System.out.println(s.length);//抛出异常 下文接收
		return "mav";//执行不到
	}

	@ExceptionHandler //这个只会处理本Controller内部的局部异常
	public ModelAndView localException(Exception e){
		ModelAndView mav = new ModelAndView();
		mav.setViewName("error1");//异常页面不能用error命名 否则跟系统默认异常界面冲突
		mav.getModel().put("exception", "异常信息是:"+e);
		return mav;
	}
	
}
//另一个Controller 要么继承 要么采用以下的标注

@ControllerAdvice//相当于所有Controller都继承了BasicController
public class BasicController {
	
	@ExceptionHandler
	public ModelAndView handlerException(Exception e){
		ModelAndView mav = new ModelAndView();
		mav.setViewName("exception");//exception.jsp
		mav.getModel().put("error", "EmpController错误消息"+e);
		return mav;
	}
	
}

  • 如果多个Controller都需要,可以封装成BasicController,之后采用继承方式重用。
  • 如果所有Controller都需要,可以封装成BasicController,之后追加@ControllerAdvice标记
五、SpringBoot REST API服务

示例代码:https://github.com/CNxielong/SpringBoot/
boot-day04-deptClient boot-day04-deptServer

1.前后分离架构
  • 前后分离:指的是将后台服务处理和前台界面进行拆分。
  • 后台服务开发者,只关注业务处理,然后将处理结果以JSON或XML通用格式返回。
  • 前台界面开发者,关注与用户交互界面的开发,调用后台服务,获取后台的JSON或XML之后,解析将其显示到界面中。
    前后端分离
2.REST API服务
  • 后台服务,一般都是采用HTTP请求和响应模式调用。 前台界面应用可以采用Ajax、HTTP工具包模式发送请求、获取服务器返回JSON或XML结果,之后解析显示到HTML界面或Android界面、IOS界面等。
  • REST是一种规则,用于限定发送HTTP请求的规则。

2.1URL设计规则
原有URL一般是按操作设计

http://localhost:8888/dept/list.do
http://localhost:8888/dept/load.do
http://localhost:8888/dept/add.do
http://localhost:8888/dept/delete.do
http://localhost:8888/dept/update.do

REST规则是按资源设计

http://localhost:8888/dept  //部门资源
http://localhost:8888/dept/1 代表: //id=1的部门资源

2.2请求提交类型
原有URL提交类型
一般是GET(无中文、参数少)和POST(中文、参数多)
REST规则提交类型

查询 : GET
添加 : POST
更新 : PUT
删除 : DELETE
http://localhost:8888/dept/1
//GET表示查询id=1的dept信息,等价于load.do
//DELETE表示删除id=1的dept信息,等价于delete.do
//PUT表示更新id=1的dept信息,等价于update.do
http://localhost:8888/dept
//GET表示查询所有的dept信息,等价于list.do
//POST表示添加dept信息,等价于add.do

2.3请求参数提交

  • 原有URL提交类型
load.do?id=xx (get提交)或post提交
  • REST提交类型
/dept/xx (将参数放置在请求URL路径中)
/dept?key=value (跟在URL后面使用key=value)

####### 2.4 post和get的区别

  • 1)提交方式:在客户端,GET方式在通过URL提交数据,数据在URL中可以看到;POST方式,数据放置在HTMLHEADER内提交。
  • 2)数据大小:GET方式数据最多只能有1024字节,而POST没有限制。
  • 3)安全性问题:正如在(1)中提到,使用 Get 的时候,参数会显示在地址栏上,而 Post 不会。所以,如果这些数据是中文数据而且是非敏感数据,那么使用 get;如果用户输入的数据不是中文字符而且包含敏感数据,那么还是使用 post为好。
  • 4)安全的和幂等的。安全:该操作用于获取信息而非修改信息。幂等:对同一URL的多个请求应该返回同样的结果。
  • GET用于查看数据,并不修改数据。比如访问新闻头条。
  • POST可能改变服务器的资源的请求,比如输入新闻评论。
    • 完整的定义并不像看起来那样严格。换句话说,GET 请求一般不应产生副作用。从根本上讲,其目标是当用户打开一个链接时,她可以确信从自身的角度来看没有改变资源。比如,新闻站点的头版不断更新。虽然第二次请求会返回不同的一批新闻,该操作仍然被认为是安全的和幂等的,因为它总是返回当前的新闻。反之亦然。POST 请求就不那么轻松了。POST表示可能改变服务器上的资源的请求。仍然以新闻站点为例,读者对文章的注解应该通过POST请求实现,因为在注解提交之后站点已经不同了)。
3.Spring Boot开发REST服务

3.1 搭建SpringBoot环境

创建maven prject
在pom.xml添加jar包定义

	<prject>
	  <mdelVersin>4.0.0</mdelVersin>
	  <grupId>cn.xdl</grupId>
	  <artifactId>dept_server</artifactId>
	  <versin>0.0.1-SNAPSHT</versin>
	  <packaging>war</packaging>
	
	  <parent>
	    <grupId>rg.springframewrk.bt</grupId>
	    <artifactId>spring-bt-starter-parent</artifactId>
	    <versin>1.4.7.RELEASE</versin>
	    <relativePath/>
	  </parent>
	
	  <prperties>
	    <prject.build.surceEncding>UTF-8</prject.build.surceEncding>
	    <prject.reprting.utputEncding>UTF-8</prject.reprting.utputEncding>
	    <java.versin>1.7</java.versin>
	  </prperties>
	
	  <dependencies>
	    <!-- bean扫描、自动配置、@bean定义 -->
	    <dependency>
	        <grupId>rg.springframewrk.bt</grupId>
	        <artifactId>spring-bt-starter</artifactId>
	    </dependency>
	
	    <!-- jdbc\连接池 -->
	    <dependency>
	        <grupId>rg.springframewrk.bt</grupId>
	        <artifactId>spring-bt-starter-jdbc</artifactId>
	    </dependency>
	
	    <!-- springbt核心ic -->
	    <dependency>
	      <grupId>rg.mybatis.spring.bt</grupId>
	      <artifactId>mybatis-spring-bt-starter</artifactId>
	      <versin>1.2.2</versin>
	    </dependency>
	
	    <!-- mvc -->
	    <dependency>
	        <grupId>rg.springframewrk.bt</grupId>
	        <artifactId>spring-bt-starter-web</artifactId>
	    </dependency>
	
	    <!-- test -->
	    <dependency>
	        <grupId>rg.springframewrk.bt</grupId>
	        <artifactId>spring-bt-starter-test</artifactId>
	        <scpe>test</scpe>
	    </dependency>
	
	    <!-- 热部署 -->
	    <dependency>
	      <grupId>rg.springframewrk.bt</grupId>
	      <artifactId>spring-bt-devtls</artifactId>
	    </dependency>
	</dependencies>
	
	</prject>

提示:ojdbc6驱动包build-path引入
添加application.properties

	#server
	server.port=8888
	
	#datasource
	spring.datasource.username=SCOTT
	spring.datasource.password=TIGER
	spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE
	spring.datasource.driver-class-name=oracle.jdbc.OracleDriver

添加主启动类MyBootAppliation.java

	@SpringBootApplication
	public class MyBootApplication {
	
	    public static void main(String[] args) {
	        SpringApplication.run(MyBootApplication.class, args);
	    }
	
	}

3.2整合Mybatis实现DeptDao

	编写实体类
	public class Dept implements Serializable{
	
	    private Integer deptn;
	    private String dname;
	    private String lc;
	    public Integer getDeptn() {
	        return deptn;
	    }
	    public vid setDeptn(Integer deptn) {
	        this.deptn = deptn;
	    }
	
	    //... ... 
	
	}

编写Mapper接口

public interface DeptDao {

    @Select("select * from dept")
    public List<Dept> findAll();

    @Select("select * from dept where deptno=#{id}")
    public Dept findById(int id);

    @Delete("delete from dept where deptno=#{id}")
    public int delete(int id);

    @Update("update dept set dname=#{dname},loc=#{loc} where deptno=#{deptno}")
    public int update(Dept dept);

    @Update("update dept set dname=#{dname} where deptno=#{deptno}")
    //接口采用@Param import org.apache.ibatis.annotations.Param;
    public int updateName(@Param("deptno")int id,@Param("dname")String name);

    @Insert("insert into dept (deptno,dname,loc) values (#{deptno},#{dname},#{loc})")
    @SelectKey(before=true,statement="select dept_seq.nextval from dual",
                resultType=Integer.class,keyProperty="deptno")//提前提取序列
    public int save(Dept dept);

}

在主启动类添加@MapperScan注解

@SpringBootApplication
@MapperScan(basePackages={"cn.xdl.boot.dao"})
public class MyBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyBootApplication.class, args);
    }

}

3.3基于mvc编写DeptController

	@RestController//搭配Rest
	public class DeptController {
	
	    @Autowired
	    private DeptDao deptDao;
	
	    @RequestMapping(value="/dept",method=RequestMethod.GET)
	    public List<Dept> loadAll(){
	        return deptDao.findAll();
	    }
	
	    @RequestMapping(value="/dept",method=RequestMethod.POST)
	    public int add(Dept dept){
	         return deptDao.save(dept);
	    }
	
	    @RequestMapping(value="/dept/{id}",method=RequestMethod.GET)
	    public Dept load(@PathVariable("id")int id){
	    //controller标注 org.springframework.web.bind.annotation.PathVariable;
	        return deptDao.findById(id);
	    }
	
	    @RequestMapping(value="/dept/{id}",method=RequestMethod.DELETE)
	    public int delete(@PathVariable("id")int id){
	        return deptDao.delete(id);
	    }
	
	    @RequestMapping(value="/dept/{id}",method=RequestMethod.PUT)
	    public int update(Dept dept){
	        return deptDao.update(dept);
	    }
	}

3.4测试REST服务

浏览器输入http://localhost:8888/dept,测试/dept查询所有的部门信息
[{"deptno":10,"dname":"JAVA","loc":null},
{"deptno":20,"dname":"RESEARCH","loc":"DALLAS"},
{"deptno":30,"dname":"SALES","loc":"CHICAGO"},
{"deptno":40,"dname":"OPERATIONS","loc":"BOSTON"}]
浏览器输入http://localhost:8888/dept/10,测试查询id=10的部门信息(浏览器默认是GET)
{"deptno":10,"dname":"JAVA","loc":null}
4.前端与端交互AJAX跨域
4.1 使用Ajax技术前后端交互
  • 1.新建Maven项目 war包项目 pom.xml文件如下
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>cn.xdl</groupId>
	<artifactId>boot-day04-deptClient</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.7.RELEASE</version>
		<relativePath />
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.7</java.version>
	</properties>

	<dependencies>
		<!-- bean扫描、自动配置、@bean定义 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<!-- mvc -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	
		<!-- 热部署 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>
		<!-- 用不到的JDBC等不要乱加,要不启动容易出错-->
	</dependencies>
</project>
  • 2.新建dept.html页面,src/main/webapp下引入JS文件夹和Jquery.js文件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="js/jquery.min.js">
	
</script>
<script type="text/javascript">
	$(function() {
		loadDept();
	});

	function loadDept() {//加载Dept的所有信息
		var str = "";
		$.ajax({
			url : "http://localhost:8888/dept",
			dataType : "json",
			type : "get",
			success : function(result) {
				//result就是返回JSON格式的结果数据
				for (var i = 0; i < result.length; i++) {
					str += "<tr><td>" + result[i].dno + "</td><td>"
							+ result[i].dname + "</td><td>" + result[i].dcity
							+ "</td><td><a href='' onclick='del("
							+ result[i].dno + ")'>删除</a></td></tr>";
					//<a href=''>A标签 href可以变成蓝灰色超链接 点击不跳转链接
					//<a href='javascript:;>A标签 href可以变成深蓝色超链接 点击跳转链接 http://localhost:9999/client/javascript;
				}
				$('#dept_table').append(str);
			},
			error : function() {
				alert("数据加载失败,AJAX跨域问题");
			}
		})
	}

	function del(id) {//对应后端Controller @Param("DNO") 
		alert(id);
		alert("del方法");
		$.ajax({
			url : "http://localhost:8888/dept/" + id,
			type : "delete",
			dataType : "json",
			success : function(result) {
				alert("删除成功");
			},
			error : function() {
				alert("删除失败");
			}
		});
	};
</script>

</head>
<body>
	<h1>部门管理</h1>
	<table id="dept_table">
	</table>
</body>
</html>
  • 3.项目/src/main/resources 新建 application.yml文件。
    • application.yml文件 注意空格
server:
 port: 9999
 context-path: /client 
4.2 AJAX跨域
  • 1.域名不同,Ajax会存在跨域问题
    localhost:9999不允许访问localhost:8888,域名不同,json结果被限制返回。

  • 解决方法分两种:

  • 方法一: 如下2.和3.都要实现

  • 2.在后台server端编写一个拦截器或过滤器

拦截器示例:implements HandlerInterceptor
package cn.xdl.boot.interceptor;

public class AjaxDomainInterceptor implements HandlerInterceptor{

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        //设置允许跨域响应的参数
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub

    }

}
  • 3.后端服务器配置拦截器或过滤器
配置拦截器示例:
package cn.xdl.boot.interceptor;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration//拦截器配置,配置AjaxDomainInterceptor拦截器
public class InterceptorConfig extends WebMvcConfigurerAdapter{

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        AjaxDomainInterceptor ajaxDomain = new AjaxDomainInterceptor();//自定义的拦截器
        registry.addInterceptor(ajaxDomain).addPathPatterns("/**");//拦截所有请求
}
}
  • 方式二:
  • 1、@WebFilter(servletNames={“dispatcherServlet”}) 标注形式 配置拦截器
package cn.xdl.ovls.course.util;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;

@WebFilter(servletNames={"dispatcherServlet"})
//@WebFilter(urlPatterns="/*");//报错
public class AjaxDomainFilter implements Filter{

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("--------AjaxDomainFilter-----------");
		//设置允许跨域响应的参数
		HttpServletResponse httpRresponse = (HttpServletResponse)response;
		httpRresponse.setHeader("Access-Control-Allow-Origin", "*");
		httpRresponse.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT");
		//放过请求处理
		chain.doFilter(request, response);
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

}

  • 2、在主入口类加@ServletComponentScan
@SpringBootApplication
@ServletComponentScan //引入组件扫描
@MapperScan(basePackages="cn.xdl.ovls.user.dao")
public class UserServiceBootApplication {

	public static void main(String[] args) {
		SpringApplication.run(UserServiceBootApplication.class, args);
	}

}
5. application.yml文件和layer插件

1.application.yml文件 注意空格

server:
 port: 9999
 context-path: /client 

2.layer插件
layer是一款近年来备受青睐的web弹层组件(jQuery弹出层插件)
链接:http://layer.layui.com/
文件名:deptLayer.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="layer/layer.js"></script>
<!-- <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> -->

<script type="text/javascript">
	$(function() {//页面加载函数
		loadDept();
	});

	function loadDept() {//加载Dept的所有信息
		var str = "";
        $.ajax({
    	url : "http://localhost:8888/dept",
    	dataType : "json",
    	cacht : "false",
    	type : "get",
    	success : function(result) {
    		$('#dept_table').empty();//清空列表
    		//result就是返回JSON格式的结果数据
    		for (var i = 0; i < result.length; i++) {
    			str += "<tr><td>"+ result[i].dno+ "</td><td>"
    			    + result[i].dnam+ "</td><td>"+ result[i].dcity 
    			    + "</td><td><a class='btn btn-danger' href='javascript:;' onclick='confirmDel("+ result[i].dno + ")'>删除</a></td></tr>";
//<a href=''>A标签 href可以变成蓝灰色超链接 点击不跳转链接
//常用<a href='javascript:;>A标签 href可以变成深蓝色超链接 点击跳转链接 http://localhost:9999/client/javascript:;
    		}
    		$('#dept_table').append(str);
    	},
    	error : function() {
    		alert("数据加载失败,AJAX跨域问题");
    	}
    	})
	}

	//确认删除函数
	function confirmDel(dno){
		//询问框
		layer.confirm('确定删除么?', {
		  btn: ['确定','不删除'] //弹出询问信息
		}, function(){//确定删除
			del(dno);
		  layer.msg('删除成功', {icon: 1});
		}, function(){//不删除
		  layer.msg('没有删除哦', {
		    time: 5000 //5s后自动关闭
// 		    btn: ['明白了', '知道了']//弹出提示
		  });
		})
	}
	
	function del(id) {//对应后端Controller @Param("DNO") 
		alert(id);
		alert("del方法");
		$.ajax({
			url : "http://localhost:8888/dept/" + id,
			type : "delete",
			dataType : "json",
			success : function(result) {
				//result返回0或1
				if (result == 1) {
// 					alert("删除成功");
					loadDept();//成功后重新加载列表
					layer.msg('删除成功');//layer修饰
				} else {
					layer.msg('删除失败');
				}
			},
			error : function() {
				alert("删除失败");
			}
		});
	};
</script>

</head>
<body>
	<div class="container"> <!-- 放到一块区域内 -->
		<h1>部门管理</h1>
		<table id="dept_table" class="table table-striped">
		</table>
	</div>
</body>
</html>
六、SpringBoot静态资源处理
1.Boot默认约定静态资源目录
  • Boot在src/main/resources,有以下几个约定目录,静态资源jpg、html、css、js放入浏览器可以直接访问。
    1.public (优先级最低) 
    2.static
    3.resources
    4.META-INF/resources(优先级最高)
    5.自定义目录优先级最高(不过需要添加配置类 见下文2.)
    每次浏览器访问静态资源,Boot会从优先级高的文件夹开始寻找。

访问方式:其中1.2.3.4 localhost:port/静态资源名(lcoal:8888/1.html不用输入public等文件名,按照加载优先级加载,新建自定义目录,也是这个执行顺序)
        其中5 localhost:port/自定义目录/静态资源名(lcoal:8888/myresources/1.html)
2.Boot自定义静态资源目录

在启动类子包下,添加配置类

@Configuration
public class ResourcesConfig extends WebMvcConfigurerAdapter{

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/myresources/**")
            .addResourceLocations("classpath:/myresources/");
    }

}
  • 提示:
    自定义目录优先级最高;如果请求是/**( /自定义文件名/**  不算),会将默认4个目录取消(但是可以访问默认目录)。建议不要映射/**请求
    
3.thymeleaf模板技术
模板技术=模板文件+数据对象==》HTML响应界面输出
velocity=.vm模板文件(VTL表达式)+数据对象 
freemark=.ftl模板文件(FTL表达式)+数据对象
thymeleaf=*.html模板文件(th表达式)+数据对象

JSP-->Servlet(EL+JSTL)-->HTML响应界面

SpringBoot对thymeleaf模板技术提供了支持,在html模板文件中可以使用th表达式直接访问ModelAndView中的Model数据。

 - 流程:/hello.do-->DispatcherServlet-->HandlerMapping-->HelloController- ->ModelAndView-->thymeleaf引擎-->/templates/hello.html(th表达式)

1.在pom.xml中引入spring-boot-starter-thymeleaf工具包、需要spring-boot-starter-web作支持

	<!-- thymeleaf -->
	<dependency>
	  <groupId>org.springframework.boot</groupId>
	  <artifactId>spring-boot-starter-thymeleaf</artifactId>
	</dependency>

2.编写HelloController

	@Controller
	public class HelloController {
	
	    @RequestMapping("/hello.do")
	    public ModelAndView say(){
	        ModelAndView mav = new ModelAndView();
	        mav.setViewName("hello");//默认/templates/hello.html模板文件
	        mav.getModel().put("msg", "Hello Thymeleaf");
	        return mav;
	    }
	
	}

3.在src/main/resources下创建templates/hello.html模板文件

	<!DOCTYPE html>
	<html xmlns:th="http://www.thymeleaf.org"> //提示:xmlns:th命名空间引入;html语法严格要求,标记有开始要有结束
	    <head>
	    <meta charset="UTF-8"/>
	    <title>Insert title here</title>
	    </head>
	    <body>
	        <h1>Thymeleaf 模板技术</h1>
	        <h2 th:text="${msg}"></h2>
	    </body>
	</html> 

4.配置application.properties
提示:thymeleaf模板文件默认位置为/templates;扩展名为.html,如果需要修改可以在application.properties中指定

spring.thymeleaf.prefix=classpath:/xxx/
spring.thymeleaf.suffix=.xxx 
例如:
spring.thymeleaf.prefix=classpath:/template/ ##默认是templates
spring.thymeleaf.suffix=.html
4.Java调用Rest服务

1.采用HttpURLConnection

	URL restURL = new URL(url);
   	HttpURLConnection conn = (HttpURLConnection) restURL.openConnection();
   	conn.setRequestMethod("POST");
   	conn.setDoOutput(true);
   	conn.getInputStream()... ...

2.采用HttpClient工具
提前下载apache的httpclient工具包,然后代码如下:
参考链接: https://blog.csdn.net/ZhuangM_888/article/details/51535549

HttpClient httpClient = new DefaultHttpClient();
HttpGet req = new HttpGet(url);
HttpResponse resp = httpClient.execute(req);
HttpEntity entity = resp.getEntity();
InputStream input = entity.getContent();

3.采用Spring提供的RestTemplate对象

  • java文件信息如下:
package cn.xdl.boot.controller;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.ModelAndView;

import cn.xdl.boot.entity.Dept;

@Controller
//@RestController
public class RestControllerA {//起名不能跟JAR包要引入的名称一致

	@Autowired//自动配置已经创建了该对象
	private RestTemplateBuilder templateBuilder;	

	
	@RequestMapping("/dept")
	public String dept(ModelMap model){
		RestTemplate restTemplate = templateBuilder.build();
		List<Dept> list = new ArrayList<Dept>();
//		调用服务器端 http://localhost:8888/deptList获取部门服务信息
		List<LinkedHashMap<String,Object>> forObject = restTemplate.getForObject("http://localhost:8888/dept", List.class);
//		get请求对应get 返回的是对象对应Object post请求对应post 返回的是链接对应url restTemplate.postForLocation(url, request);		
//		System.out.println("forObject类型:"+forObject.getClass());
//		Object obj = forObject.get(0);
//		System.out.println(obj);
//		System.out.println("obj类型:"+obj.getClass());
//		System.out.println("obj类型:"+obj.getClass().getName());//LinkedHashMap类型
		for (LinkedHashMap<String,Object> map : forObject) {
			list.add(new Dept((Integer)map.get("dno"), (String)map.get("dname"), (String)map.get("dcity")));
		}
		model.put("deptList", list);
		return "hello";//找到  application.properties下的 配置prefix suffix
		
	}
	
	
	@RequestMapping("/dept/beanUtils")//需要在MAVEN中引入beanUtils组件
	public String showDeptList(ModelMap model){
		System.out.println("进入了/dept");
		RestTemplate restTemplate = templateBuilder.build();
		System.out.println("restTemplate");
		List<Dept> list = new ArrayList<Dept>();
		//调用服务器端 http://localhost:8888/deptList获取部门服务信息
		List<LinkedHashMap<String,Object>> forObject = restTemplate.getForObject("http://localhost:8888/dept", List.class);
		//get请求对应get 返回的是对象对应Object post请求对应post 返回的是链接对应url restTemplate.postForLocation(url, request);		

		for (LinkedHashMap<String,Object> map : forObject) {
			Dept dept = new Dept();
			//将map对象信息封装成Dept对象
			try {
				BeanUtils.populate(dept, map);
			} catch (IllegalAccessException | InvocationTargetException e) {
				e.printStackTrace();
			}//map中的key和dept中的属性名一致
			list.add(dept);
			
		}
		model.put("deptList", list);
		return "hello";//找到  application.properties下的 配置prefix suffix
		
	}
	
}

  • 要使用BeanUtils pom.xml文件需要导入
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
</dependency>
七、SpringBoot对JavaWeb支持 @ServletComponentScan
1.Servlet组件@WebServlet

1.1 编写Servlet组件,然后追加@WebServlet标记

package cn.xdl.boot.sservice;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;//pom.xml导入

/**
 * 
 * @Title: MyServlet  
 * @Description: TODO(SpringBoot对JavaWeb支持 @WebServlet)  
 * @author X-Dragon  
 * @date 2018年10月31日 下午6:01:49 
 * @version V1.0  
 *
 */
//@WebServlet(name="webServlet")//可以 不规范
//@WebServlet(urlPatterns={"/myservlet.do"})//区分大小写
@WebServlet(urlPatterns="/myservlet.do",name="myservlet")//与下文拦截器匹配
public class MyServlet extends HttpServlet {

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO 不设置编码格式中文乱码
	    request.setCharacterEncoding("utf-8");//请求编码
	    response.setCharacterEncoding("utf-8");//响应编码
	    response.setContentType("text/html;charset=utf-8");//设置响应编码类型

		String name = request.getParameter("name");
		PrintWriter out = response.getWriter();
		//pom.xml文件 引入了Apache Commons Lang » 3.4
		if(StringUtils.isNotBlank(name)){//非空
			out.println("Hello "+name);
		}else{//为空
			out.println("Hello 空字符串");
		}
		out.close();
	}
	
}

1.2在主启动类前添加@ServletComponentScan

	@SpringBootApplication
	@ServletComponentScan//扫描servlet组件
	public class MyBootApplication {
	
	    public static void main(String[] args) {
	        SpringApplication.run(MyBootApplication.class, args);
	    }
	
	}
2.Filter组件@WebFilter
  1. 编写Filter组件,追加@WebFilter注解
package cn.xdl.boot.service;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

//@WebFilter(servletNames={"myservlet"})//指定要拦截的请求名称
@WebFilter(urlPatterns={"/myservlet.do"})//制定拦截器请求路径 这两种都行
public class MyFilter implements Filter {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		System.out.println("初始化过滤器");
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		response.setCharacterEncoding("UTF-8");
		chain.doFilter(request, response);
		System.out.println("--执行Filter--");
		
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		System.out.println("Filter destory");
	}

}

2.主入口类添加@ServletComponentScan

3.Listener组件@WebListener
  1. 编写Listener组件,追加@WebListener标记
	@WebListener
	public class MyListener 
	implements ServletContextListener,HttpSessionListener{//监听Servlet和Session
	
	    ServletContext application;//
	    // 执行顺序application contextInitialized  sessionCreated
	
	    @Override
	    public void contextInitialized(ServletContextEvent arg0) {
	        application = arg0.getServletContext();
	        application.setAttribute("count", 0);
	    }
	
	    @Override
	    public void contextDestroyed(ServletContextEvent arg0) {
	        application.removeAttribute("count");
	    }
	
	    @Override
	    public void sessionCreated(HttpSessionEvent arg0) {
	        Integer count = (Integer)application.getAttribute("count");
	        count++;
	        application.setAttribute("count", count);
	    }
	
	    @Override
	    public void sessionDestroyed(HttpSessionEvent arg0) {
	        Integer count = (Integer)application.getAttribute("count");
	        count--;
	        application.setAttribute("count", count);
	    }
	
	}

新建Servlet,URL输入http://localhost:9999/myservlet1 调用Session显示用户数

@WebServlet(urlPatterns={"/myservlet1"})//区分大小写
public class MyServlet1 extends HttpServlet {

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO 不设置编码格式中文乱码
	    request.setCharacterEncoding("utf-8");//请求编码
	    response.setCharacterEncoding("utf-8");//响应编码
	    response.setContentType("text/html;charset=utf-8");//设置响应编码类型

		String name = request.getParameter("name");
		PrintWriter out = response.getWriter();
		//pom.xml文件 引入了Apache Commons Lang » 3.4
		if(StringUtils.isNotBlank(name)){//非空
			out.println("Hello "+name);
		}else{//为空
			out.println("Hello 空字符串");
		}
		Integer count = (Integer)request.getServletContext().getAttribute("count");//只写这一行不会触发
		request.getSession();//获取一下Session
		out.println("在线用户数"+count);
		out.close();
	}
	
}

主入口类添加@ServletComponentScan

4.SpringBoot使用AOP

代码路径:/SpringBoot/boot-dayo4-static

  1. 在pom.xml中追加spring-boot-starter-aop工具包支撑
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. 编写切面组件,然后使用@Aspect、@Before、@Around、切入点表达式等
package cn.xdl.boot.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

@Component
@Aspect
public class WatchBean {
	
//    @Around("within(cn.xdl.boot.controller..*)")
	@Around(value="within(cn.xdl.boot.controller..*)")//标记要切入的Controller类
	public Object watch(ProceedingJoinPoint pjp) throws Throwable {//ProceedingJoinPoint pjp封装切入方法的信息
		System.out.println("前置通知执行");
		StopWatch sw = new StopWatch();//记录服务调用时间
		sw.start();
		Object obj = pjp.proceed();//执行调用目标组件方法(Controller的方法) obj封装方法返回值
		sw.stop();
		long time = sw.getTotalTimeMillis();//记录服务调用时间 第一次时间久
		Object target = pjp.getTarget();
	    //记录服务调用时间、处理时间、服务组件名、方法名等信息
		System.out.println("pjp.getTarget():"+target);//输出 pjp.getTarget():cn.xdl.boot.controller.DeptController@58fd1503
        String targetName = pjp.getTarget().getClass().getName();//目标组件名 cn.xdl.boot.controller.DeptController 
        String methodName = pjp.getSignature().getName();//目标方法名 loadAll
        System.out.println("执行的组件为:"+targetName+" 方法为:"+methodName+" 返回结果:"+obj+" 处理时长:"+time);
		return obj;//返回的结果就是请求返回的结果 此处是DEPT集合
	}
	
}
八、SpringBoot 定时任务和监控
1.SpringBoot定时任务调度

1.启动立刻执行的任务
1.1 编写任务实现类,实现CommandLineRunner接口

2.	@Component
3.	public class MyTask1 implements CommandLineRunner{
4.	
5.	    @Override
6.	    public void run(String... args) throws Exception {
7.	        System.out.println("开始执行任务1");
8.	    }
9.	
10.	}

1.2 编写任务实现类,实现ApplicationRunner接口

	@Component
	@Order(2)
	public class MyTask2 implements ApplicationRunner{
	
	    @Override
	    public void run(ApplicationArguments args) throws Exception {
	        System.out.println("开始执行任务2");
	    }
	
	}

提示:多个任务时,可以使用@Order(2)指定任务调用顺序,1、2、3…。

2.定时周期性调用任务
1.编写任务类,追加@EnableScheduling和@Scheduled标记

	@Component
	@EnableScheduling//启用定时计划
	public class MyTask3 {
	
	    @Scheduled(cron="0/5 * * * * ?")//每隔5秒中调用一次。
	    public void run(){
	        System.out.println("定时执行任务3:"+new Date());
	    }
	
	}

2.corn表达式
参考下面资料
Corn表达式:https://www.cnblogs.com/javahr/p/8318728.html

2.SpringBoot actuator监控
  • 1.pom.xml引入依赖包
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.0.4.RELEASE</version>
</dependency>
  • 2.重新编译maven 启动主启动类,展示如下信息
    1.png-251.9kB

  • 3.浏览器输入:

http://localhost:8888/mappings 显示出系统映射信息
http://localhost:8888/health  显示出系统健康信息
3.SpringBoot druid监控

druid连接池监控.png-302.2kB

  • 1.pom.xml引入依赖包
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.0.4.RELEASE</version>
</dependency>
  • 2.配置数据源访问信息 application.properties文件
#server
server.port=8888

#datasource
spring.datasource.username=system
spring.datasource.password=123456
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver

#druid
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
  • 3.写Druid Servlet和Filter实现类或者DruidConfig
package cn.xdl.boot.druid;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

import com.alibaba.druid.support.http.StatViewServlet;

@WebServlet( urlPatterns = "/druid/*", initParams = {
		@WebInitParam(name = "exclusions", value = "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"), // 忽略资源
		@WebInitParam(name = "loginUsername", value = "system"), //用户名大小写敏感 如果写错了会直接登录 不需要密码
		@WebInitParam(name = "loginPassword", value = "123456") })//密码

public class DruidStatViewServlet extends StatViewServlet {

	/**
	 * serialVersionUID
	 */
	private static final long serialVersionUID = 1L;

}
package cn.xdl.boot.druid;

import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;

import com.alibaba.druid.support.http.WebStatFilter;


@WebFilter(filterName = "druidFilter", urlPatterns = "/*", initParams = {
		@WebInitParam(name = "exclusion", value = "*.js,*.gif,*.jpg,*.bmp,*.css,*.png,*.ico,/druid/*") }) // 忽略资源

public class DruidStatFilter extends WebStatFilter {

}

  • DruidConfig
@Configuration
public class DruidConfig {
	
	@Value("${spring.datasource.url}")
	private String dbUrl;
	
	@Value("${spring.datasource.username}")
	private String username;
	
	@Value("${spring.datasource.password}")
	private String password;
	
	@Value("${spring.datasource.driver-class-name}")
	private String driverClassName;

	
	@Bean
	public DataSource createDruid(){
		DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(dbUrl);
        datasource.setUsername(username);
        datasource.setPassword(password);
        datasource.setDriverClassName(driverClassName);
        try {
            datasource.setFilters("stat");//启动sql监控
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return datasource;
	}
	
}

  • 4.主启动类追加@ServletComponentScan
package cn.xdl.boot;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@MapperScan(basePackages={"cn.xdl.boot.dao"})//接口文件类没有标注需要制定包名
@ServletComponentScan//带@标记组件的不需要指定包名
public class MyBootApplication {
	public static void main(String[] args) {
		SpringApplication.run(MyBootApplication.class, args);
		System.out.println("服务器端:8888启动");
	}
}

补充:Maven 中央仓库地址

1、http://www.sonatype.org/nexus/ 私服nexus工具使用
2、http://mvnrepository.com/ (推荐)
3、http://repo1.maven.org/maven2
4、http://maven.aliyun.com/nexus/content/groups/public/ 阿里云 (强力推荐)
5、http://repo2.maven.org/maven2/ 私服nexus工具使用
6、http://uk.maven.org/maven2/
7、http://repository.jboss.org/nexus/content/groups/public
8、http://maven.oschina.net/content/groups/public/ oschina可惜啦,以前一直用这个,不过现在有阿里云来擦屁股啦
9、http://mirrors.ibiblio.org/maven2/
10、http://maven.antelink.com/content/ repositories/central/
11、http://nexus.openkoala.org/nexus/content/groups/Koala-release/
12、http://maven.tmatesoft.com/content/groups/public/
其实,国内maven镜像虽然快,但是更新比较慢,国外的仓库由于国内网络的原因,下载简直不能忍,但是更新很快,可以根据自身的情况选择,有些人会花些钱开代理访问外网比较快,建议使用原装。下面是maven库配置
oschina-repo 开源中国镜像 central 可以根据自己的网络情况选填上面的url
补充:
测试

1.pom.xml文件配置信息

 <!-- test -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>

2.Junit测试类代码


package cn.xdl.boot.user.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import cn.xdl.ovls.user.UserServerBootApplicaiton;
import cn.xdl.ovls.user.dao.UserMapper;
import cn.xdl.ovls.user.entity.User;

@RunWith(SpringRunner.class)
@SpringBootTest(classes=UserServerBootApplicaiton.class)
public class TestUserDao {

	@Autowired
	private UserMapper userDao;

	
	@Test// run as Junit test
	public void TestSelect(){
		User user = userDao.selectByPrimaryKey(1);
		if(user != null){
			System.out.println(user);
		}else{
			System.out.println("查询结果为空");
		}
	}
	
}

3、主入口类加@MapperScanner标注

package cn.xdl.ovls.user;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan //引入组件扫描
@MapperScan(basePackages="cn.xdl.ovls.user.dao")//指定DAO 接口位置
public class UserServerBootApplicaiton {

	public static void main(String[] args) {
		SpringApplication.run(UserServerBootApplicaiton.class, args);
	}

}

4.MOCKMVC测试
image.png-106.2kB
image.png-32.5kB

package cn.xdl.ovls.user.controller.test;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import cn.xdl.ovls.user.UserServiceBootApplication;
import cn.xdl.ovls.user.controller.UserController;
/**
 * 
 * @Title: TestUserController  
 * @Description: TODO(MockMVC测试)  
 * @author X-Dragon  [email protected]
 * @version V1.0  
 *
 */
@RunWith(SpringRunner.class) //固定写法
@SpringBootTest(classes={UserServiceBootApplication.class})
public class TestUserController {

	@Autowired
	private UserController userController;
	private MockMvc mockmvc;
	
	@Before
	public void init(){
		//创建MockMVC对象
		mockmvc = MockMvcBuilders.standaloneSetup(userController).build();
	}
	
	@Test
	public void test1() throws Exception{
		MockHttpServletRequestBuilder postRequest = MockMvcRequestBuilders.post("/user/token") //设置提交方式
				.param("name", "xielong") //设置变量
				.param("password", "123456");
		//执行请求,获取返回结果
		MvcResult mvcResult = mockmvc.perform(postRequest).andReturn();
		//获取返回结果内容打印输出
		String body = mvcResult.getResponse().getContentAsString();
		System.out.println("查询结果是"+body);

	}
}
标注区分

1、@RequestParam和@PathVariable和@PathParam
区分标注: https://blog.csdn.net/u011410529/article/details/66974974
https://blog.csdn.net/a67474506/article/details/46361195
代码:https://github.com/CNxielong/SpringBoot/tree/master/boot

  • @RequestParam 和 @PathVariable 注解是用于从request中接收请求的,两个都可以接收参数,关键点不同的是@RequestParam 是从request里面拿取值,而 @PathVariable 是从一个URI模板里面来填充。
    • @PathVariable是获取请求路径中的变量作为参数
    • @RequestParam注解是获取静态URL传入的参数
 @PathVariable:变量 http://localhost:8888/boot/pathVariable/bigsea
 @RequestMapping("/pathVariable/{name}")
	public String pathVariable(@PathVariable("name")String name)

 @RequestParam:参数 http://localhost:8888/boot/requestParam?firstName=big&lastName=sea
 @RequestMapping("/requestParam")
    public String requestParam(@RequestParam(value="firstName",required=false)String firstName,
		@RequestParam( value="lastName" ,required = true) String lastName,
		@RequestParam(value="age",required = false ,defaultValue="0")int age)	

看下面一段代码:

@RestController
public class Controller {
	
	/**
	 * http://localhost:8888/boot/pathVariable/bigsea
	 * http://localhost:8888/boot/pathVariable/sea
	 * http://localhost:8888/boot/pathVariable?name=xielong报错
	 * 这些URL 都会 执行此方法 并且将  <b>bigsea</b>、<b>sea</b> 作为参数 传递到name字段
	 * @param name
	 * @return
	 */
	@RequestMapping("/pathVariable/{name}")
	public String pathVariable(@PathVariable("name")String name){
		System.out.println("hello "+name); //在控制台打印
		return "helloworld"+"/pathVariable/"+name;//在页面上打印出来
	}

	/**
	 * http://localhost:8888/boot/requestParam?firstName=big&lastName=sea
	 * http://localhost:8888/boot/requestParam?lastName=sea&age=23
	 * http://localhost:8888/boot/requestParam 报错400 Required String parameter 'lastName' is not present
	 * 如果 required = true 则表示请求参数对应的字段必须存在.如果不存在则会抛出异常<br/>
	 * @param firstName 可以为null
	 * @param lastName 不能为null .为null报异常
	 * @param age age字段表示如果没有 age 参数 则默认值为 0 
	 * @return
	 */
	@RequestMapping("/requestParam")
	public String requestParam(@RequestParam(value="firstName",required=false)String firstName,
			@RequestParam( value="lastName" ,required = true) String lastName,
			@RequestParam(value="age",required = false ,defaultValue="0")int age) {
		System.out.println("hello my name is " + (firstName == null ? "" : firstName)
										+ lastName + "," + age +" years old this year");
		return "helloworld";
	}

}
  • @RequestParam
http://localhost:8080/springmvc/hello/101?param1=10&param2=20
  • 根据上面的这个URL,你可以用这样的方式来进行获取
public String getDetails(
    @RequestParam(value="param1", required=true) String param1,
        @RequestParam(value="param2", required=false) String param2){
...
}

@RequestParam 支持下面四种参数

defaultValue 如果本次请求没有携带这个参数,或者参数为空,那么就会启用默认值
name 绑定本次参数的名称,要跟URL上面的一样
required 这个参数是不是必须的
value 跟name一样的作用,是name属性的一个别名
  • @PathVariable
http://localhost:8888/boot/pathVariable/bigsea
  • 根据上面的这个URL,你可以用这样的方式来进行获取
     http://localhost:8888/boot/pathVariable/bigsea
	 http://localhost:8888/boot/pathVariable/sea

	/**
	 * http://localhost:8888/boot/pathVariable/bigsea
	 * http://localhost:8888/boot/pathVariable/sea
	 * http://localhost:8888/boot/pathVariable?name=xielong报错
	 * 这些URL 都会 执行此方法 并且将  <b>bigsea</b>、<b>sea</b> 作为参数 传递到name字段
	 * @param name
	 * @return
	 */
	@RequestMapping("/pathVariable/{name}")
	public String pathVariable(@PathVariable("name")String name){
		System.out.println("hello "+name); //在控制台打印
		return "helloworld"+"/pathVariable/"+name;//在页面上打印出来
	}
  • @PathVariable
    这个注解能够识别URL里面的一个模板,我们看下面的一个URL
http://localhost:8080/springmvc/hello/101?param1=10&param2=20

上面的一个url你可以这样写:

@RequestMapping("/hello/{id}")
    public String getDetails(@PathVariable(value="id") String id,
    @RequestParam(value="param1", required=true) String param1,
    @RequestParam(value="param2", required=false) String param2){
.......
}

区别很明显了

  • @PathParam

    • 这个注解是和spring的pathVariable是一样的,也是基于模板的,但是这个是jboss包下面的一个实现,上面的是spring的一个实现,都要导包
  • @QueryParam

    • @QueryParam 是 JAX-RS 本来就提供的,和Spring的RequestParam作用一致
  • @ResponseBody

    • responseBody表示服务器返回的时候以一种什么样的方式进行返回, 将内容或对象作为 HTTP 响应正文返回,值有很多,一般设定为json
  • @RequestBody

    • 一般是post请求的时候才会使用这个请求,把参数丢在requestbody里面
@RequestMapping匹配符
  • (1)支持标准的的URL
  • (2)带{xxx}占位符的URL
比如:
    /user/{userId} 可匹配user/123 user/abc
   /company/{companyId}/user/{userId}/detail 可匹配/company/123/user/456/detail
  • (3)Ant风格的URL(? * **)
– ?:匹配文件名中的一个字符

– *:匹配文件名中的任意字符

– **:** 匹配多层路径

实例:

URL : /user/*/create
-- /user/bigsea/create 、 /user/sea/create 等URL

URL : /user/**/create
-- /user/big/sea/create 、 /user/sea/big/create 等URL

URL : /user/create??
-- /user/createaa 、/user/createbb

SpringCloud

1.png-42.1kB
2.png-37.3kB

1、简介:

  • Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

2、环境搭建:

  • 1、在pom.xml引入spring-cloud开发包
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>cn.xdl</groupId>
  <artifactId>ovls_eureka_server</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  	  <!-- springboot-parent -->
	  <parent>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-parent</artifactId>
	    <version>1.4.7.RELEASE</version>
	    <relativePath/>
	  </parent>
  	
	  <properties>
	    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	    <java.version>1.7</java.version>
	  </properties>
	
	  <dependencies>
	    <!-- springcloud-eureka-server 注册中心用server 要调用的服务去掉server-->
	    <dependency>
	      <groupId>org.springframework.cloud</groupId>
	      <artifactId>spring-cloud-starter-eureka-server</artifactId>
	      <version>1.3.4.RELEASE</version>
	    </dependency>
	
	  </dependencies>
	
	  <!-- springcloud-parent -->
	  <dependencyManagement>
	    <dependencies>
	        <dependency>
	          <groupId>org.springframework.cloud</groupId>
	          <artifactId>spring-cloud-starter-parent</artifactId>
	          <version>Brixton.SR5</version>
	          <type>pom</type>
	        </dependency>
	    </dependencies>
	  </dependencyManagement>
  
</project>
  • 2、在application.properties配置eureka
#server
server.port=2222

#eureka spring.application.name推荐全英文字符、区分大小写。不要写"_ -"等非法字符 
spring.application.name=EurekaServer
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=false
eureka.client.serviceUrl.defaultZone=http://localhost:2222/eureka
  • 3、在主启用类追加@EnabledEurekaServer标记
package cn.xdl.ovls;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer//启用eureka服务器
@SpringBootApplication
public class EurekaServerBootApplication {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SpringApplication.run(EurekaServerBootApplication.class, args);
	}

}

  • 4、浏览器可以输入http://localhost:2222/ 跳转到Eureka界面

3、将REST服务注册到Cloud的eureka

1.在需要使用Cloud的子项目(ovls_user_server和ovls_user_paper)中的pom.xml中追加spring-cloud-eureka定义

	<!-- springcloud-parent 这个放在单独的位置 放在dependencies外-->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-parent</artifactId>
				<version>Brixton.SR5</version>
				<type>pom</type>
			</dependency>
		</dependencies>
	</dependencyManagement>
	
	<!-- springcloud-eureka-server dependencies内部-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka-server</artifactId>
			<version>1.3.4.RELEASE</version>
		</dependency>

user_server和paper_server服务调用Cloud。user_server的POM.xml如下

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>cn.xdl</groupId>
	<artifactId>ovls_user_server</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.7.RELEASE</version>
		<relativePath />
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.7</java.version>
	</properties>

	<!-- springcloud-parent -->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-parent</artifactId>
				<version>Brixton.SR5</version>
				<type>pom</type>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<dependencies>
		<!-- bean扫描、自动配置、@bean定义 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<!-- aop -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

		<!-- 健康监控 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>

		<!-- jdbc\连接池 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>

		<!-- springboot核心mybatis -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.2.2</version>
		</dependency>

		<!-- mvc -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!-- test -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- 热部署 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>

		<!-- 引入druid连接池 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.1.6</version>
		</dependency>

		<!-- mysql驱动 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<!-- springcloud-eureka-server -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka-server</artifactId>
			<version>1.3.4.RELEASE</version>
		</dependency>

	</dependencies>

</project>

2.在application.properties添加eureka注册参数

#Eureka spring.application.name不能写一些非法字符"- _"推荐纯字母 大小写敏感
spring.application.name=USERSERVER
eureka.client.serviceUrl.defaultZone=http://localhost:2222/eureka

user_server的如下

#server
server.port=8881

#dataSource
spring.datasource.username=root
spring.datasource.password=123123
spring.datasource.url=jdbc:mysql://localhost:3306/studyonline?useUnicode=true&characterEncoding=utf8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

#Eureka spring.application.name不能写一些非法字符"- _"推荐纯字母 大小写敏感
spring.application.name=USERSERVER
eureka.client.serviceUrl.defaultZone=http://localhost:2222/eureka
#是否将自己注册到Eureka Server上,默认为true
eureka.client.register-with-eureka=false
#是否从Eureka Server上获取注册信息,默认为true
eureka.client.fetch-registry=false 

#Druid
#spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

3.在主启动类追加@EabledDiscoveryClient

@EnableEurekaServer
@SpringBootApplication
@ServletComponentScan //引入组件扫描
@MapperScan(basePackages="cn.xdl.ovls.user.dao")
public class UserServiceBootApplication {

	public static void main(String[] args) {
		SpringApplication.run(UserServiceBootApplication.class, args);
	}

}

4.浏览器输入IP+Port访问注册中心.注意paper_server也要注册,图片没有显示。
Eureka.png-180.5kB

4、从Cloud查找调用REST服务

1.使用RestTemplate(ribbon负载)

1.在需要使用RestTemplate的项目(paper_Server)中pom.xml中定义ribbon开发包

		<!-- springcloud-ribbon  -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-ribbon</artifactId>
			<version>1.3.4.RELEASE</version>
		</dependency>

2.定义一个RestTemplate配置,启用ribbon负载

package cn.xdl.ovls.paper.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
	
	@Bean
	@LoadBalanced//启用ribbon负载均衡调用策略
	public RestTemplate createRestTemplate(){
		return new RestTemplate();
	}
}

3.在需要使用RestTemplate的类中用Autowired注入,调用eureka服务

@Component
public class CheckLoginInterceptor implements HandlerInterceptor{

	@Autowired//找到config下的 RestTemplate
	private RestTemplate restTemplate;
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		//获取请求带过来的token
		String token = request.getParameter("token");
		System.out.println("调用/user/token服务检查token是否合法"+token);
		response.setContentType("application/json;charset=UTF-8");
		
		if(token != null && !"".equals(token)){
			//调用/user/token服务检查token是否合法,合法就返回true,不合法返回false
			//调用ovls_course_server的服务查询所有学科信息 ovls_user_server替代原先的IP和端口号
			ResponseResult userResult  = restTemplate.getForObject(
				"http://USERSERVER/user/token?token="+token, ResponseResult.class);
			System.out.println(userResult);
			if(userResult.getStatus()==1){//通过验证,表示token合法
				return true;
			}
		}
		//未通过验证
		PrintWriter out = response.getWriter();
		out.println("{\"stauts\":2,\"msg\":\"不合法用户\"}");
		out.close();
		return false;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO Auto-generated method stub
		
	}

}
2.feign模式
  1. 在需要用fegin的项目的pom.xml中定义ribbon、feign(底层也是ribbon)开发包。
	<!-- springcloud-ribbon -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-ribbon</artifactId>
		<version>1.3.4.RELEASE</version>
	</dependency>

	<!-- springcloud-feign -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-feign</artifactId>
		<version>1.3.4.RELEASE</version>
	</dependency>

ovls_paper_server全部pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>cn.xdl</groupId>
  <artifactId>ovls_paper_server</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
    <parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.4.7.RELEASE</version>
	<relativePath/>
  </parent>
  
  <properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<java.version>1.7</java.version>
  </properties>
  
	<!-- springcloud-parent 这个放在单独的位置 放在dependencies外-->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-parent</artifactId>
				<version>Brixton.SR5</version>
				<type>pom</type>
			</dependency>
		</dependencies>
	</dependencyManagement>

  <dependencies>
		<!-- bean扫描、自动配置、@bean定义 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		
		<!-- aop -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

		<!-- 健康监控 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>

		<!-- jdbc\连接池 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
  
  		<!-- springboot核心mybatis -->
  		<dependency>
		  <groupId>org.mybatis.spring.boot</groupId>
		  <artifactId>mybatis-spring-boot-starter</artifactId>
		  <version>1.2.2</version>
		</dependency>
  
  		<!-- mvc -->
  		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<!-- test -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		
		<!-- 热部署 -->
  		<dependency>
		  <groupId>org.springframework.boot</groupId>
		  <artifactId>spring-boot-devtools</artifactId>
		</dependency>
		
		<!-- 引入druid连接池 -->
		<dependency>
		  <groupId>com.alibaba</groupId>
		  <artifactId>druid</artifactId>
		  <version>1.1.6</version>
		</dependency>
		
		<!-- mysql驱动 -->
		<dependency>
		  <groupId>mysql</groupId>
		  <artifactId>mysql-connector-java</artifactId>
		</dependency>
		
        <!-- 分页插件 https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>		
        
		<!-- springcloud-eureka-server dependencies内部-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka-server</artifactId>
			<version>1.3.4.RELEASE</version>
		</dependency>
		
		<!-- springcloud-ribbon -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-ribbon</artifactId>
			<version>1.3.4.RELEASE</version>
		</dependency>

		<!-- springcloud-feign -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-feign</artifactId>
			<version>1.3.4.RELEASE</version>
		</dependency>
        
  </dependencies>
  
</project>

2.定义一个Fegin远程调用接口

package cn.xdl.ovls.paper.remote;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

import cn.xdl.ovls.paper.util.ResponseResult;

/**
 * 
 * @Title: UserServiceRemote  
 * @Description: TODO(FeignClient对应哪个服务实例)  
 * @author X-Dragon  
 * @version V1.0  
 *
 */
@FeignClient(name="USERSERVER")//对应微服务的 服务端名称
public interface UserServiceRemote {
	//调用 http://USERSERVER/user/token?token= 
	//有参数需要用value
	//method设置请求方式,不设置默认是GET
	@RequestMapping(value="/user/token",method=RequestMethod.GET)
	ResponseResult checkToken(String token);
		
}

3.在需要用Feign的Class文件中,远程接口对象,使用服务

	@Autowired
	private UserServiceRemote userRemote;
	
	//利用Remote对象调用服务
	ResponseResult userResult = userRemote.checkToken(token);

CheckLoginInterceptor中用到了Feign接口

@Component
public class CheckLoginInterceptor implements HandlerInterceptor{

	@Autowired//找到remote包下的UserServiceRemote接口
	private UserServiceRemote userServiceRemote;
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		//获取请求带过来的token
		String token = request.getParameter("token");
		System.out.println("调用/user/token服务检查token是否合法"+token);
		response.setContentType("application/json;charset=UTF-8");
		
		if(token != null && !"".equals(token)){
			//调用/user/token服务检查token是否合法,合法就返回true,不合法返回false
			//调用figen接口的实现类 直接RPC调用方法
			ResponseResult userResult  = userServiceRemote.checkToken(token);
			System.out.println(userResult);
			if(userResult.getStatus()==1){//通过验证,表示token合法
				return true;
			}
		}
		//未通过验证
		PrintWriter out = response.getWriter();
		out.println("{\"stauts\":2,\"msg\":\"不合法用户\"}");
		out.close();
		return false;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO Auto-generated method stub
		
	}

}

4.在主入口启动类前追加@EnableFeignClients标记

package cn.xdl.ovls.paper;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@EnableFeignClients// 用到Feign
@EnableEurekaClient// @EnableEurekaClient包含@EnableDiscoveryClient 此处可以用EnableDiscoveryClient代替
//@EnableDiscoveryClient
@SpringBootApplication
@MapperScan(basePackages="cn.xdl.ovls.paper.dao")
@ServletComponentScan //引入组件扫描
public class PaperServiceBootApplication {

	public static void main(String[] args) {
		SpringApplication.run(PaperServiceBootApplication.class, args);
	}

}

常见报错
    1. 【SpringCloud】com.sun.jersey.api.client.ClientHandlerException
  • 参考:https://www.cnblogs.com/zmblog/p/8777878.html
  • 原因:默认配置情况,eureka会把自己当成客户端注册自己,只开了客户端没开服务器端。
  • 解决:1、先启动注册中心、后启动服务客户端 或者 2、修改application.properties配置文件
eureka.client.register-with-eureka=false #是否将自己注册到Eureka Server上,默认为true
eureka.client.fetch-registry=false #是否从Eureka Server上获取注册信息,默认为true

Mybatis

1、转义字符

转义字符.png-16.2kB

第一种写法:
原符号       <        <=      >       >=       &        '        "
替换符号    &lt;    &lt;=   &gt;    &gt;=   &amp;   &apos;  &quot;
例如:sql如下:
create_date_time &gt;= #{startTime} and  create_date_time &lt;= #{endTime}

第二种写法:

大于等于:<![CDATA[ >= ]]>
小于等于:<![CDATA[ <= ]]>
例如:sql如下:
create_date_time <![CDATA[ >= ]]> #{startTime} and  create_date_time <![CDATA[ <= ]]> #{endTime}


Mybatis转义字符表
&lt;	<	小于
&gt;	>	大于
&amp;	&	与
&apos;	'	单引号
&quot;	"	双引号
需要注意的是分号是必不可少的。 比如 a > b 我们就写成  a &gt; b

当然啦, 我们也可以用另外一种,就是 <![CDATA[ ]]> 符号。 在mybatis中这种符号将不会解析。 比如

<![CDATA[ when min(starttime)<='12:00' and max(endtime)<='12:00' ]]>

猜你喜欢

转载自blog.csdn.net/xielong0509/article/details/83240658