SpringBoot
第二章、Spring Boot環境搭建
- SpringBoot是對Spring框架的封裝,實現了Spring應用的快速開發,可以使用IOC、AOP、MVC以及跟其他技術整合。去除了XML配置文件,一切採用Java配置(註解)。
對應代碼路徑:
https://github.com/CNxielong/SpringBoot.git
一、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
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容器。
項目代碼包結構
建議採用如下包結構組織代碼
提示:@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.默認自動配置
-
- SpringBoot可以通過自動配置創建出DataSource對象;程序員也可以手動創建。
需要引入spring-boot-starter-jdbc數據庫訪問部分的jar包支持。
- SpringBoot可以通過自動配置創建出DataSource對象;程序員也可以手動創建。
-
-
1.SpringBoot默認連接池
SpringBoot可以默認創建連接池對象,創建出的對象id名爲dataSource.創建機制如下: -
優先創建tomcat-jdbc連接池對象。
(需要引入spring-boot-starter-jdbc.jar包支持) -
沒有tomcat-jdbc,會創建HikariCP連接池對象
(需要引入hikaricp.jar支持) -
沒有HikariCP,會創建dbcp連接池對象
(需要引入dbcp.jar支持) -
沒有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整合結構
示例代碼: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
- 啓動MyBootApplication測試,瀏覽器輸入:http://localhost:xxx/hello.do
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
- 編寫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
- 編寫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
- 在pom.xml中追加spring-boot-starter-aop工具包支撐
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 編寫切面組件,然後使用@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 啓動主啓動類,展示如下信息
-
3.瀏覽器輸入:
http://localhost:8888/mappings 顯示出系統映射信息
http://localhost:8888/health 顯示出系統健康信息
3.SpringBoot druid監控
- 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啓動");
}
}
- 5.瀏覽器輸入鏈接地址 http://localhost:8888/druid/index.html 輸入用戶和密碼
補充: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測試
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¶m2=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¶m2=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、簡介:
- 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也要註冊,圖片沒有顯示。
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模式
- 在需要用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);
}
}
常見報錯
-
- 【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、轉義字符
第一種寫法:
原符號 < <= > >= & ' "
替換符號 < <= > >= & ' "
例如:sql如下:
create_date_time >= #{startTime} and create_date_time <= #{endTime}
第二種寫法:
大於等於:<![CDATA[ >= ]]>
小於等於:<![CDATA[ <= ]]>
例如:sql如下:
create_date_time <![CDATA[ >= ]]> #{startTime} and create_date_time <![CDATA[ <= ]]> #{endTime}
Mybatis轉義字符表
< < 小於
> > 大於
& & 與
' ' 單引號
" " 雙引號
需要注意的是分號是必不可少的。 比如 a > b 我們就寫成 a > b
當然啦, 我們也可以用另外一種,就是 <![CDATA[ ]]> 符號。 在mybatis中這種符號將不會解析。 比如
<![CDATA[ when min(starttime)<='12:00' and max(endtime)<='12:00' ]]>