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='' οnclick='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:;' οnclick='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' ]]>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章