關於IDEA中建立springboot+security+jpa
首先本文章不會分析框架的底層程式碼只是幫助小白快速搭建專案,因為官方文件都寫的明明白白,其中spring Security安全框架可能有部分小白看不懂官方文件
廢話不多說了進入正題:因為springboot推薦使用Maven(依賴管理框架) 如何使用springboot呢? 在maven的專案目錄src/main/java下建立BootApplication類(可以改名)
BootApplication類 (該類是springboot的入口類用於啟動springboot):@EnableTransactionManagement //用於開啟事務註解 @SpringBootApplication//Springboot的啟動入口類 @EnableWebSecurity //啟用web安全 //@Configuration //@Import({ // DispatcherServletAutoConfiguration.class, // EmbeddedServletContainerAutoConfiguration.class, // ErrorMvcAutoConfiguration.class, // HttpEncodingAutoConfiguration.class, // HttpMessageConvertersAutoConfiguration.class, // JacksonAutoConfiguration.class,// JmxAutoConfiguration.class, // MultipartAutoConfiguration.class, // ServerPropertiesAutoConfiguration.class, // PropertyPlaceholderAutoConfiguration.class, // ThymeleafAutoConfiguration.class, // WebMvcAutoConfiguration.class, // WebSocketAutoConfiguration.class, // //})//用於自定義載入哪些類 public classBootApplication extends SpringBootServletInitializer{ public static void main(String[] args) { SpringApplication.run(BootApplication.class, args); }}
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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>com</groupId> <artifactId>boot</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>boot</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <!--此包是themeleaf模板所需jar包--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity4</artifactId> </dependency> <!--web應用所需的包--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--此包用於簡化程式碼可以使用註解自動生成get set等方法--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> </dependency> <!--此包用於對資料庫操作基於hibernate--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!--阿里連線池所需包--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.25</version> </dependency> <!--spring安全框架包--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
現在只需要建一個Controller類即可
@RestController public class Rest { @Autowired private TestService testService; @Secured("ROLE_user") @RequestMapping("/v1/{name}")//Rest Api風格 //@PathVariable用於獲取Url上的引數 public List<User> boot(@PathVariable String name) { List<User> list=testService.findAll(); System.out.println(list.get(0).getUrole()); String data = "{\"name\":\"張三\"}"; return list; } }
@RestController是springboot中的新增註解用於開發restful風格api介面 該註解相當於@Controller和@ResponseBody 合用返回的是json格式資料
因為springboot內建了tomcat所以只需要執行BootApplocation類 輸入 localhost:8080/v1/name 即可在瀏覽器中返回{“name”:“張三”}的資料
是不是相當簡單,沒有ssh或ssm那麼多繁瑣的配置檔案,也不需要在web中配置mvc,spring
如果你想使用資料庫,springboot提供了jpa用於操作資料庫(至於什麼是jpa,簡單說jpa是貌似2006年5月提出的一種ORM持久化規範,它只是一種規範,而我們最常用的hibernate是對jpa的實現,也叫jpa產品) springboot的jpa是基於hibernate的但是他進行了進一步封裝,使開發人員更好的與資料庫進行互動,首先需要在pom.xml中加入依賴(上面的依賴已經假如,請看上邊的pom) 在springboot的配置檔案中加入
#配置資料庫 spring.datasource.url=jdbc:mysql://localhost:3306/springboot spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.username=root spring.datasource.password=abc spring.datasource.driver-class-name=com.mysql.jdbc.Driver
在建立bean
//@Getter @Setter 是lok外掛中用於幫助自動建立getset方法還有許多註解等用 如果使用@Data //@Min 是用於欄位驗證的註解 /*@Data :註解在類上;提供類所有屬性的 getting 和 setting 方法,此外還提供了equals、canEqual、hashCode、toString 方法 @Setter:註解在屬性上;為屬性提供 setting 方法 @Getter:註解在屬性上;為屬性提供 getting 方法 @Log4j :註解在類上;為類提供一個 屬性名為log 的 log4j 日誌物件 @NoArgsConstructor:註解在類上;為類提供一個無參的構造方法 @AllArgsConstructor:註解在類上;為類提供一個全參的構造方法 @Transient表示屬性不與資料庫對映 */ @Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Getter @Setter private Integer uid; @NotBlank(message = "使用者名稱不能為空") @Column(name = "username") @Getter @Setter private String username; @NotBlank(message = "密碼不能為空") @Column(name = "password") @Getter @Setter private String password; @NotNull(message = "年齡不能為空")//NotNull用於基本資料型別 @Min(value =18,message = "年齡必須大於等於18") @Column(name = "sage") @Getter @Setter private Integer sage; /* @NotNull(message = "性別不能為空")*/ @Column(name = "ssex") @NotBlank(message = "性別不為空")//只能用於String @Getter @Setter private String ssex; @Column(name = "urole") @JsonIgnore //在json序列化時忽略該屬性 因為在懶載入時候返回json資料時會出現錯誤重複載入 @ManyToMany(cascade = CascadeType.REFRESH,fetch = FetchType.LAZY)//optional設定外來鍵是否可以為空 @JoinTable(name ="u_r",joinColumns ={@JoinColumn(name = "uid")},inverseJoinColumns = {@JoinColumn(name = "rid")}) @Getter @Setter private Set<Role> urole=new HashSet<Role>(); }
可能有注意到為什麼屬性沒有get set方法,因為我是用來lombok這個jar,它可以使用註解來自動生成get set用於簡化程式碼
,接著我們新建DaoImpl介面繼承JpaRepository(該類已經實現了簡單的crud操作我們無需實現Test介面)如果你想自己寫sql可以使用@Query註解在方法上按jpa規定的格式建立方法例如下面的findByUsername方法(沒有使用@Query是因為這個方法太簡單框架幫我們實現了)
public interface Test extends JpaRepository<User,Long>{ User findByUsername(String username); }
在Server層我們直接呼叫Test介面即可
@Autowired private Test test; public List<User> findAll() { return test.findAll(); }
在controller中呼叫test即可實現全查
接下來看如何使用security
原來在ssh中使用security中首先匯入匯入security的包接著在web中配置代理過濾器
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在配置security的配置檔案
<?xml version="1.0" encoding="UTF-8"?><b:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
<!-- 配置不攔截登陸頁面 由於從3.1開始不再支援filters="none"-->
<http pattern="/index.jsp" security="none"></http>
<http pattern="/*.js" security="none"></http>
<!-- 開啟攔截連 use-expressions="false"用於關閉表示式的許可權控制-->
<http auto-config="true" use-expressions="true" >
<!-- 配置自定義登入頁面 -->
<form-login login-page="/index.jsp" authentication-failure-forward-url="/index.jsp" default-target-url="/success.jsp" />
<!-- 配置攔截規則 -->
<intercept-url pattern="/success.jsp" access="hasAnyRole('ROLE_USER','ROLE_admin')"/>
<!-- 關閉跨域訪問 -->
<csrf disabled="true"/>
<!-- 配置session超時跳轉頁面 -->
<session-management invalid-session-url="/index.jsp">
<!-- 最大允許1個使用者登入 -->
<!-- <concurrency-control max-sessions="2" error-if-maximum-exceeded="true"/> -->
</session-management>
<!--許可權不夠跳轉頁面 繼承AccessDeniedHandler自定義403頁面-->
<access-denied-handler ref="accessDeniedServletHandler"/>
<!-- 登出 -->
<logout logout-url="/logout" logout-success-url="/index.jsp" invalidate-session="true" delete-cookies="JSESSIONID"/>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="authenticationProvider">
<!-- <user-service >
配置多個使用者
<user name="user" password="123456" authorities="ROLE_USER" />
<user name="user1" password="123456" authorities="ROLE_ccc" />
</user-service> -->
</authentication-provider>
</authentication-manager>
<!-- 註冊authenticationManager用於載入錯誤資訊 -->
<b:bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
<b:property name="messageSource" ref="messageSource"></b:property>
</b:bean> <b:bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<b:property name="hideUserNotFoundExceptions" value="false"></b:property>
<b:property name="userDetailsService" ref="security"></b:property>
</b:bean>
<!-- 修改spring security的預設國際化資原始檔 -->
<b:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<b:property name="basename" value="classpath:messages_zh_CN"></b:property>
</b:bean>
</b:beans>
看到上面的配置檔案是不是眼花 沒關係springboot與security高度整合 (web配置?不需要,xml?不需要)我們來零配置來使用security
首先我們在BootApplocation上用
@EnableWebSecurity 開啟Web
建立一個類繼承 WebSecurityConfigurerAdapter
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled = true) //開啟方法許可權註解 public class WebSecurityConfig extends WebSecurityConfigurerAdapter { /* @Autowired private AuthenticationManager authenticationManager;*///如果想讓許可權註解生效必須加註入此bean @Autowired private MyAccessDeniedHandle myAccessDeniedHandle; @Autowired private MySecurity mySecurity; @Override public void configure(WebSecurity web) throws Exception { //配置靜態資源不攔截 web.ignoring().antMatchers("/static/**", "/**/*.jsp"); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/","/excep").permitAll()//配置不攔截Url .anyRequest().authenticated() .and()//相當於結束標籤 .formLogin() .loginPage("/") .loginProcessingUrl("/action_security")//必須是post請求 如果為Get不生效 .usernameParameter("username") .passwordParameter("password")//配置登陸頁面 .successForwardUrl("/login") .failureUrl("/") .permitAll()//所有使用者都能訪問這個頁面 .and() .rememberMe() .userDetailsService(mySecurity) .tokenValiditySeconds(90000) .key("abc") .rememberMeParameter("rememberMe") .rememberMeCookieName("zxl") .and() .exceptionHandling() .accessDeniedHandler(myAccessDeniedHandle)//配置403許可權頁面 myAccessDeniedHandl自定義bean 如果不想自定義可以簡單的使用.accessDeniedPage()指定403頁面 .and() .logout() .invalidateHttpSession(false) .permitAll() .and() .csrf().disable();//關閉csrf 如果開啟後登出只能使用post請求用於防止別人偽造logout } //使用BCrypt密碼加密 @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } /* //異常訊息載入類 @Bean public ReloadableResourceBundleMessageSource bundleMessageSource(){ ReloadableResourceBundleMessageSource bundleMessageSource=new ReloadableResourceBundleMessageSource(); bundleMessageSource.setBasename("classpath:messages_zh_CN"); return bundleMessageSource; } @Bean //自定義的驗證類 public DaoAuthenticationProvider daoAuthenticationProvider(){ DaoAuthenticationProvider daoAuthenticationProvider=new DaoAuthenticationProvider(); daoAuthenticationProvider.setHideUserNotFoundExceptions(false); daoAuthenticationProvider.setPasswordEncoder(passwordEncoder()); daoAuthenticationProvider.setUserDetailsService(mySecurity); return daoAuthenticationProvider; } //載入異常訊息 @Bean public ProviderManager providerManager(){ List<AuthenticationProvider> list=new ArrayList<>(); list.add(daoAuthenticationProvider()); ProviderManager providerManager=new ProviderManager(list); providerManager.setMessageSource(bundleMessageSource()); return providerManager; }*/ @Bean //自定義的驗證類 public DaoAuthenticationProvider daoAuthenticationProvider(){ DaoAuthenticationProvider daoAuthenticationProvider=new DaoAuthenticationProvider(); daoAuthenticationProvider.setHideUserNotFoundExceptions(false);//用於捕捉使用者不存在異常 daoAuthenticationProvider.setPasswordEncoder(passwordEncoder()); daoAuthenticationProvider.setUserDetailsService(mySecurity); return daoAuthenticationProvider; } }
該類相當於Security中xml配置檔案 如果想使用xml與其混合使用可以使用@Configuration註解來引用xml
原來使用security的自定義國際化需要配置bean 現在無需配置只需要在maven的resources資料夾建立一個空的messages.properties 在建立一個messages_zh_CN.properties資料夾org/springframework/security/spring-security-core/4.2.3.RELEASE/spring-security-core-4.2.3.RELEASE.jar!/org/springframework/security/messages_zh_CN.properties
中複製到剛才的zh_CN資料夾中即可自定義異常訊息