SpringBoot 後臺權限框架搭建(一)—後臺框架搭建
SpringBoot後臺權限管理系統(二)—前端工程搭建
SpringBoot後臺權限管理系統(三)—權限模塊
SpringBoot後臺權限管理系統(四)—部署css
<!-- swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--// swagger2 -->
複製代碼
package com.site.mountain;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class Swagger2 {
//swagger2的配置文件,這裏能夠配置swagger2的一些基本的內容,好比掃描的包等等
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())//調用apiInfo方法,建立一個ApiInfo實例,裏面是展現在文檔頁面信息內容
.select()
//控制暴露出去的路徑下的實例
//若是某個接口不想暴露,可使用如下註解
//@ApiIgnore 這樣,該接口就不會暴露在 swagger2 的頁面下
.apis(RequestHandlerSelectors.basePackage("com.site.mountain.controller"))
.paths(PathSelectors.any())
.build();
}
//構建 api文檔的詳細信息函數,注意這裏的註解引用的是哪一個
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
//頁面標題
.title("Spring Boot 測試使用 Swagger2 構建RESTful API")
//建立人
.contact(new Contact("MarryFeng", "http://www.baidu.com", ""))
//版本號
.version("1.0")
//描述
.description("API 描述")
.build();
}
}
複製代碼
map.put("/swagger-ui.html", "anon");
map.put("/swagger-resources", "anon");
map.put("/swagger-resources/configuration/security", "anon");
map.put("/swagger-resources/configuration/ui", "anon");
map.put("/v2/api-docs", "anon");
map.put("/webjars/springfox-swagger-ui/**", "anon");
複製代碼
在類上:@Api(value = "sysuser", description = "系統用戶類")html
@Api(value = "sysuser", description = "系統用戶類")
@Controller
@RequestMapping("/sysuser")
public class SysUserController {...}
複製代碼
在方法上:前端
@ApiOperation(value = "adduser",httpMethod="POST",notes = "用戶添加",response = JSONObject.class)java
@ApiOperation(value = "adduser",httpMethod="POST",notes = "用戶添加",response = JSONObject.class)
@RequestMapping(value = "adduser", method = RequestMethod.POST)
public void addUser(){....}
複製代碼
在參數上: @ApiParam(value = "前端傳遞過來的用戶對象",required = true)mysql
@ApiOperation(value="edit", notes="用戶編輯", httpMethod = "POST",response = JSONObject.class)
@RequestMapping(value = "edit",method = RequestMethod.POST)
public void update(@RequestBody @ApiParam(value = "前端傳遞過來的用戶對象",required = true) SysUser sysUser){...}
複製代碼
詳細用法請參考swagger2的apigit
頁面顯示:訪問地址爲http://localhost:8080/mt/swagger-ui.htmlgithub
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.2</version>
</dependency>
<!-- 該依賴必加,裏面有sping對schedule的支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
複製代碼
數據庫表導入:由於須要quartz的數據庫表,由於最新版本沒有數據庫表,因此我使用的是2.2.2
版本,web
把quartz-2.2.2-distribution.tar.gz\quartz-2.2.2\docs\dbTables
文件夾下的表導入數據庫中spring
配置文件:sql
# 固定前綴org.quartz
# 主要分爲scheduler、threadPool、jobStore、plugin等部分
#
#
#org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
# 實例化ThreadPool時,使用的線程類爲SimpleThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# threadCount和threadPriority將以setter的形式注入ThreadPool實例
# 併發個數
org.quartz.threadPool.threadCount = 5
# 優先級
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.jobStore.misfireThreshold = 5000
# 默認存儲在內存中
#org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
#持久化
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = qzDS
org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL = jdbc:mysql://192.168.75.1:3306/mountain?useUnicode=true&characterEncoding=UTF-8
org.quartz.dataSource.qzDS.user = root
org.quartz.dataSource.qzDS.password = root
org.quartz.dataSource.qzDS.maxConnections = 10
複製代碼
前端頁面展現
後端controller
package com.site.mountain.controller.sys;
import com.github.pagehelper.PageInfo;
import com.site.mountain.entity.JobAndTrigger;
import com.site.mountain.entity.JobBean;
import com.site.mountain.job.BaseJob;
import com.site.mountain.service.IJobAndTriggerService;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping(value = "/job")
public class JobController {
@Autowired
private IJobAndTriggerService iJobAndTriggerService;
//加入Qulifier註解,經過名稱注入bean
@Autowired
private Scheduler scheduler;
private static Logger log = LoggerFactory.getLogger(JobController.class);
@PostMapping(value = "/addjob")
public Map addjob(@RequestBody JobBean jobBean) throws Exception {
Map map = new HashMap();
map.put("code", 20000);
map.put("state", 30000);
try{
addJob(jobBean.getJobClassName(), jobBean.getJobGroupName(), jobBean.getCronExpression());
}catch (Exception e){
e.printStackTrace();
map.put("state", 30001);
}
return map;
}
public void addJob(String jobClassName, String jobGroupName, String cronExpression) throws Exception {
// 啓動調度器
scheduler.start();
//構建job信息
JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(jobClassName, jobGroupName).build();
//表達式調度構建器(即任務執行的時間)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
//按新的cronExpression表達式構建一個新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName, jobGroupName)
.withSchedule(scheduleBuilder).build();
try {
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
System.out.println("建立定時任務失敗" + e);
throw new Exception("建立定時任務失敗");
}
}
@PostMapping(value = "/pausejob")
public Map pausejob(@RequestBody JobBean jobBean) throws Exception {
Map map = new HashMap();
map.put("code", 20000);
map.put("state", 30000);
try {
jobPause(jobBean.getJobClassName(), jobBean.getJobGroupName());
} catch (Exception e) {
e.printStackTrace();
map.put("state", 30001);
}
return map;
}
public void jobPause(String jobClassName, String jobGroupName) throws Exception {
scheduler.pauseJob(JobKey.jobKey(jobClassName, jobGroupName));
}
@PostMapping(value = "/resumejob")
public Map resumejob(@RequestBody JobBean jobBean) throws Exception {
Map map = new HashMap();
map.put("code", 20000);
map.put("state", 30000);
try {
jobresume(jobBean.getJobClassName(), jobBean.getJobGroupName());
} catch (Exception e) {
e.printStackTrace();
map.put("state", 30001);
} finally {
}
return map;
}
public void jobresume(String jobClassName, String jobGroupName) throws Exception {
scheduler.resumeJob(JobKey.jobKey(jobClassName, jobGroupName));
}
@PostMapping(value = "/reschedulejob")
public Map rescheduleJob(@RequestBody JobBean jobBean) throws Exception {
Map map = new HashMap();
map.put("code", 20000);
map.put("state", 30000);
try {
jobreschedule(jobBean.getJobClassName(), jobBean.getJobGroupName(), jobBean.getCronExpression());
} catch (Exception e) {
e.printStackTrace();
map.put("state", 30001);
}
return map;
}
public void jobreschedule(String jobClassName, String jobGroupName, String cronExpression) throws Exception {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
// 表達式調度構建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 按新的cronExpression表達式從新構建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger從新設置job執行
scheduler.rescheduleJob(triggerKey, trigger);
} catch (SchedulerException e) {
System.out.println("更新定時任務失敗" + e);
throw new Exception("更新定時任務失敗");
}
}
@PostMapping(value = "/deletejob")
public Map deletejob(@RequestBody JobBean jobBean) throws Exception {
Map map = new HashMap();
map.put("code", 20000);
map.put("state", 30000);
try {
jobdelete(jobBean.getJobClassName(), jobBean.getJobGroupName());
} catch (Exception e) {
e.printStackTrace();
map.put("state", 30001);
}
return map;
}
public void jobdelete(String jobClassName, String jobGroupName) throws Exception {
scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));
scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));
scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));
}
@RequestMapping(value = "/queryjob")
public Map<String, Object> queryjob(@RequestBody JobBean jobBean) {
PageInfo<JobAndTrigger> jobAndTrigger = iJobAndTriggerService.getJobAndTriggerDetails(jobBean.getPageNum(), jobBean.getPageSize());
Map<String, Object> map = new HashMap<String, Object>();
map.put("JobAndTrigger", jobAndTrigger);
map.put("number", jobAndTrigger.getTotal());
map.put("code", 20000);
return map;
}
public static BaseJob getClass(String classname) throws Exception {
Class<?> class1 = Class.forName(classname);
return (BaseJob) class1.newInstance();
}
}
複製代碼
定時器接口
package com.site.mountain.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public interface BaseJob extends Job {
@Override
void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException;
}
複製代碼
package com.site.mountain.job.impl;
import com.site.mountain.job.BaseJob;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
public class HelloJob implements BaseJob {
private static Logger _log = LoggerFactory.getLogger(HelloJob.class);
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
_log.error("Hello Job執行時間: " + new Date());
}
}
複製代碼
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
複製代碼
#配置監控統計攔截的filters,去掉後監控界面SQL沒法進行統計,'wall'用於防火牆
spring.datasource.mysql.filters=stat,wall
spring.datasource.mysql.driverClassName=com.mysql.jdbc.Driver
spring.datasource.mysql.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.mysql.url=jdbc:mysql://127.0.0.1:3306/mountain
spring.datasource.mysql.username=root
spring.datasource.mysql.password=root
複製代碼
MysqlDataSourceConfig
類中數據源應用到的類都修改成Druid對應的類@Configuration
@MapperScan(basePackages = "com.site.mountain.dao.mysql", sqlSessionTemplateRef = "mysqlSqlSessionTemplate")
public class MysqlDataSourceConfig {
// @Primary 肯定此數據源爲master
@Bean(name = "mysqlDataSource")
@ConfigurationProperties(prefix = "spring.datasource.mysql")
@Primary
public DruidDataSource mysqlDataSource() {
return DruidDataSourceBuilder.create().build();
}
//....
}
複製代碼
DruidConfig.java
package com.site.mountain.datasource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DruidConfig {
/** * 註冊servlet信息,配置監控圖 */
@Bean
@ConditionalOnMissingBean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean servletRegistrationBean =
new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
//白名單
servletRegistrationBean.addInitParameter("allow", "172.22.112.130");
//IP黑名單(存在共同時,deny優先於allow) : 若是知足deny的話提示:Sorry, you are not permitted to view this page.
servletRegistrationBean.addInitParameter("deny", "127.0.0.1");
//用於登錄的帳號密碼
servletRegistrationBean.addInitParameter("loginUsername", "admin");
servletRegistrationBean.addInitParameter("loginPassword", "admin");
//是否能重置數據
servletRegistrationBean.addInitParameter("resetEnable", "true");
return servletRegistrationBean;
}
/** * 註冊filter信息,用於攔截 */
@Bean
@ConditionalOnMissingBean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
}
複製代碼
訪問[http://172.22.112.130:8080/mt/druid ] 用戶名密碼是admin/admin。注意訪問地址ip須要與DruidConfig類中的配置白名單一致,否則不能訪問
訪問Druid監控頁面URL時,系統必須先登陸,由於shiro攔截了訪問,可是在shiro放開druid/**
訪問攔截,會致使系統主頁面等連接不能訪問,待解決...
<!-- Docker maven plugin -->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.2.0</version>
<configuration>
<!-- docker私服的地址 -->
<dockerHost>http://192.168.75.129:2375</dockerHost>
<!--鏡像名稱以及版本號-->
<imageName>mountain:1.0.0</imageName>
<!--依賴的基礎鏡像-->
<baseImage>java</baseImage>
<!--Dockerfile的位置 -->
<dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>
<!-- 這裏是複製 jar 包到 docker 容器指定目錄配置 -->
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
<!-- Docker maven plugin -->
複製代碼
# FROM:指明當前鏡像繼承的基鏡像,編譯當前鏡像時候會自動下載基鏡像
FROM java:8
# MAINTAINER:當前鏡像的做者和郵箱,使用空格隔開
MAINTAINER jinshw jinshw@xxx.com
# VOLUME:掛載目錄
VOLUME /ROOT # ADD:從當前工做目錄複製文件到鏡像目錄中並從新命名
ADD mountain-0.0.1-SNAPSHOT.jar mountain.jar # RUN:在當前鏡像上執行Linux命令,這裏我執行了2個run指令,第二個run指令是爲了解決容器和宿主機時間不一致的問題
RUN bash -c 'touch /mountain.jar'
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo 'Asia/Shanghai' >/etc/timezone
# EXPOSE:監聽的端口號
EXPOSE 8080
# ENTRYPOINT:讓容器像一個可執行程序同樣運行
ENTRYPOINT ["java", "-jar", "mountain.jar"] 複製代碼
docker-maven-plugin
/usr/lib/systemd/system
路徑下ExecStart=/usr/bin/dockerd -H unix://var/run/docker.sock -H tcp://0.0.0.0:2375
clean compile install -DskipTests docker:removeImage docker:build