搭建Spring Boot+Spring security

先來(lái)一波個(gè)人理解

Spring security權(quán)限驗(yàn)證流程圖

首先由WebSecurityConfig.class初始化用戶配置纷捞,可以配置登錄痢虹、登出、自定義的過(guò)濾器主儡、靜態(tài)資源等奖唯,然后由MyFilterSecurityIntercepyor.class攔截?cái)r截所有請(qǐng)求,然后分別進(jìn)行攔截驗(yàn)證和權(quán)限驗(yàn)證糜值,首先由MyInvocationSecurityMetadataSourceService.class判斷該請(qǐng)求是否需要攔截(是否需要權(quán)限驗(yàn)證)丰捷,如果不需要?jiǎng)t通過(guò),如果需要?jiǎng)t發(fā)送到MyAccessDecisionManager.class寂汇,由用戶自動(dòng)定義的CustomUserService.class獲取用戶信息病往,進(jìn)行權(quán)限驗(yàn)證,至此權(quán)限驗(yàn)證完畢骄瓣。

1. 搭建數(shù)據(jù)庫(kù)

/*Table structure for table `sys_permission` */

DROP TABLE IF EXISTS `sys_permission`;

CREATE TABLE `sys_permission` (
  `id` int(11) NOT NULL,
  `name` varchar(50) DEFAULT NULL,
  `descritpion` varchar(50) DEFAULT NULL,
  `url` varchar(50) DEFAULT NULL,
  `pid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `sys_permission` */

insert  into `sys_permission`(`id`,`name`,`descritpion`,`url`,`pid`) values (1,'HOME','home','/',NULL),(2,'ADMIN','ABel','/admin',NULL);

/*Table structure for table `sys_permission_role` */

DROP TABLE IF EXISTS `sys_permission_role`;

CREATE TABLE `sys_permission_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_id` int(11) DEFAULT NULL,
  `permission_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

/*Data for the table `sys_permission_role` */

insert  into `sys_permission_role`(`id`,`role_id`,`permission_id`) values (1,1,1),(2,1,2),(3,2,1);

/*Table structure for table `sys_role` */

DROP TABLE IF EXISTS `sys_role`;

CREATE TABLE `sys_role` (
  `id` int(11) NOT NULL,
  `name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `sys_role` */

insert  into `sys_role`(`id`,`name`) values (1,'ROLE_ADMIN'),(2,'ROLE_USER');

/*Table structure for table `sys_role_user` */

DROP TABLE IF EXISTS `sys_role_user`;

CREATE TABLE `sys_role_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `sys_user_id` int(11) DEFAULT NULL,
  `sys_role_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

/*Data for the table `sys_role_user` */

insert  into `sys_role_user`(`id`,`sys_user_id`,`sys_role_id`) values (1,1,1),(2,2,2);

/*Table structure for table `sys_user` */

DROP TABLE IF EXISTS `sys_user`;

CREATE TABLE `sys_user` (
  `id` int(11) NOT NULL,
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `sys_user` */

insert  into `sys_user`(`id`,`username`,`password`) values (1,'admin','admin'),(2,'abel','abel');

2. 搭建項(xiàng)目停巷,引入pom文件

<?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.myspring.security</groupId>
    <artifactId>mysecuritydemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>mysecuritydemo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>
        <!-- 在thymeleaf中擴(kuò)展spring secutity (頁(yè)面權(quán)限配置)-->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
            <resources>
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.properties</include>
                        <include>**/*.xml</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
            </resources>
    </build>


</project>

3. 逆向生成表信息,實(shí)現(xiàn)UserDetailsService.class

/**
  * @author lht
  * @doc   自定義用戶信息
  * @date 2018/6/1
*/
@Service
public class CustomUserService implements UserDetailsService {
    @Autowired
    SysUserMapper sysUserMapper;
    @Autowired
    SysPermissionMapper sysPermissionMapper;
    @Autowired
    SysRoleMapper sysRoleMapper;
    private Logger log= LoggerFactory.getLogger(this.getClass());
    @Override
    public UserDetails loadUserByUsername(String username) {

        SysUser user = sysUserMapper.findByUserName(username);

        if (user != null) {
            List<SysPermission> permissions = sysPermissionMapper.findByAdminUserId(user.getId());
            List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
            List<SysRole> roles = sysRoleMapper.findRoleByUserid(user.getId());
            for (SysRole role : roles) {
                if (!StringUtils.isEmpty(role.getName())) {
                    log.info("role.getName():"+role.getName());
                    GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getName());
                    //此處將角色信息添加到 GrantedAuthority 對(duì)象中榕栏,在后面進(jìn)行全權(quán)限驗(yàn)證時(shí)會(huì)使用GrantedAuthority 對(duì)象畔勤。
                    grantedAuthorities.add(grantedAuthority);
                }
            }
            for (SysPermission permission : permissions) {
                if (permission != null && permission.getName()!=null) {

                    GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());
                    //1:此處將權(quán)限信息添加到 GrantedAuthority 對(duì)象中,在后面進(jìn)行全權(quán)限驗(yàn)證時(shí)會(huì)使用GrantedAuthority 對(duì)象臼膏。
                    grantedAuthorities.add(grantedAuthority);
                }
            }
            return new User(user.getUsername(), user.getPassword(), grantedAuthorities);
        } else {
            throw new UsernameNotFoundException("admin: " + username + " do not exist!");
        }

    }
}

4. 實(shí)現(xiàn)AccessDecisionManager.class


/**
  * @author lht
  * @doc   權(quán)限判斷
  * @date 2018/6/1
*/
@Service
public class MyAccessDecisionManager implements AccessDecisionManager {

    // decide 方法是判定是否擁有權(quán)限的決策方法硼被,
    //authentication 是釋CustomUserService中循環(huán)添加到 GrantedAuthority 對(duì)象中的權(quán)限信息集合.
    //object 包含客戶端發(fā)起的請(qǐng)求的requset信息,可轉(zhuǎn)換為 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
    //configAttributes 為MyInvocationSecurityMetadataSource的getAttributes(Object object)這個(gè)方法返回的結(jié)果渗磅,此方法是為了判定用戶請(qǐng)求的url 是否在權(quán)限表中嚷硫,如果在權(quán)限表中此疹,則返回給 decide 方法柑爸,用來(lái)判定用戶是否有此權(quán)限融痛。如果不在權(quán)限表中則放行谭羔。
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {

        if(null== configAttributes || configAttributes.size() <=0) {
            return;
        }
        ConfigAttribute c;
        String needRole;
        for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {
            c = iter.next();
            needRole = c.getAttribute();
            for(GrantedAuthority ga : authentication.getAuthorities()) {//authentication 為在注釋1 中循環(huán)添加到 GrantedAuthority 對(duì)象中的權(quán)限信息集合
                if(needRole.trim().equals(ga.getAuthority())) {
                    return;
                }
            }
        }
        throw new AccessDeniedException("no right");
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}

5. 實(shí)現(xiàn)FilterInvocationSecurityMetadataSource.class


/**
  * @author lht
  * @doc   設(shè)置攔截url權(quán)限和判斷權(quán)限
  * @date 2018/6/1
*/
@Service
public class MyInvocationSecurityMetadataSourceService  implements
        FilterInvocationSecurityMetadataSource {

    @Autowired
    private SysPermissionMapper sysPermissionMapper;

    private HashMap<String, Collection<ConfigAttribute>> map =null;

    /**
     * 加載權(quán)限表中所有權(quán)限
     */
    public void loadResourceDefine(){
        map = new HashMap<>();
        Collection<ConfigAttribute> array;
        ConfigAttribute cfg;
        List<SysPermission> permissions = sysPermissionMapper.findAll();
        for(SysPermission permission : permissions) {
            array = new ArrayList<>();
            cfg = new SecurityConfig(permission.getName());
            //此處只添加了用戶的名字栅组,其實(shí)還可以添加更多權(quán)限的信息榆俺,例如請(qǐng)求方法到ConfigAttribute的集合中去谒臼。此處添加的信息將會(huì)作為MyAccessDecisionManager類的decide的第三個(gè)參數(shù)艇挨。
            array.add(cfg);
            //用權(quán)限的getUrl() 作為map的key会烙,用ConfigAttribute的集合作為 value负懦,
            map.put(permission.getUrl(), array);
        }

    }

    //此方法是為了判定用戶請(qǐng)求的url 是否在權(quán)限表中筒捺,如果在權(quán)限表中,則返回給 decide 方法纸厉,用來(lái)判定用戶是否有此權(quán)限系吭。如果不在權(quán)限表中則放行。
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        if(map ==null) loadResourceDefine();
        //object 中包含用戶請(qǐng)求的request 信息
        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
        AntPathRequestMatcher matcher;
        String resUrl;
        for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {
            resUrl = iter.next();
            matcher = new AntPathRequestMatcher(resUrl);
            if(matcher.matches(request)) {
                return map.get(resUrl);
            }
        }
        return null;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}

6. 繼承AbstractSecurityInterceptor.class同時(shí)實(shí)現(xiàn)Filter.class


/**
  * @author lht
  * @doc 攔截器(所有權(quán)限驗(yàn)證的調(diào)用轉(zhuǎn)發(fā)地)
  * @date 2018/6/1
*/
@Component
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

    @Autowired
    private FilterInvocationSecurityMetadataSource securityMetadataSource;

    @Autowired
    public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {
        super.setAccessDecisionManager(myAccessDecisionManager);
    }


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        FilterInvocation fi = new FilterInvocation(request, response, chain);
        invoke(fi);
    }


    public void invoke(FilterInvocation fi) throws IOException, ServletException {
//fi里面有一個(gè)被攔截的url
//里面調(diào)用MyInvocationSecurityMetadataSource的getAttributes(Object object)這個(gè)方法獲取fi對(duì)應(yīng)的所有權(quán)限
//再調(diào)用MyAccessDecisionManager的decide方法來(lái)校驗(yàn)用戶的權(quán)限是否足夠
        InterceptorStatusToken token = super.beforeInvocation(fi);
        try {
//執(zhí)行下一個(gè)攔截器
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } finally {
            super.afterInvocation(token, null);
        }
    }

    @Override
    public void destroy() {

    }

    @Override
    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;
    }

    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return this.securityMetadataSource;
    }
}

7. 繼承WebSecurityConfigurerAdapter.class


/**
  * @author lht
  * @doc   security 規(guī)則配置
  * @date 2018/6/1
*/

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)//開(kāi)啟security的注解模式
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    /**
      * @author lht
      * @doc   加載自定義獲得用戶信息(根據(jù)username)
      * @date 2018/6/1
    */
    @Bean
    UserDetailsService customUserService(){ //注冊(cè)UserDetailsService 的bean
        return new CustomUserService();
    }


    /**
      * @author lht
      * @doc   設(shè)置密碼為明文(在實(shí)際項(xiàng)目中不行)
      * @date 2018/6/1
    */
    @Bean
    PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserService()); //user Details Service驗(yàn)證

    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated() //任何請(qǐng)求,登錄后可以訪問(wèn)
                .and()
                .formLogin()
                .loginPage("/login")
                .failureUrl("/login?error")
                .permitAll() //登錄頁(yè)面用戶任意訪問(wèn)
                .and()
                .logout().permitAll(); //注銷(xiāo)行為任意訪問(wèn)

        // 范例
       /* http.authorizeRequests()
                //靜態(tài)資源和一些所有人都能訪問(wèn)的請(qǐng)求
                .antMatchers("/css/**","/staic/**", "/js/**","/images/**").permitAll()
                .antMatchers("/", "/login","/session_expired").permitAll()
                //登錄
                .and().formLogin()
                .loginPage("/login")
                .usernameParameter("userId")       //自己要使用的用戶名字段
                .passwordParameter("password")     //密碼字段
                .defaultSuccessUrl("/index")     //登陸成功后跳轉(zhuǎn)的請(qǐng)求,要自己寫(xiě)一個(gè)controller轉(zhuǎn)發(fā)
                .failureUrl("/loginAuthtictionFailed")  //驗(yàn)證失敗后跳轉(zhuǎn)的url
                //session管理
                .and().sessionManagement()
                .maximumSessions(1)                //系統(tǒng)中同一個(gè)賬號(hào)的登陸數(shù)量限制
                .and().and()
                .logout()//登出
                .invalidateHttpSession(true)  //使session失效
                .clearAuthentication(true)    //清除證信息
                .and()
                .httpBasic();*/
    }
}

8. 實(shí)現(xiàn)登錄頁(yè)面(注:在開(kāi)始沒(méi)有更改默認(rèn)配置的情況下颗品,用戶名和密碼只能是username和password)

<!DOCTYPE html>
<html  xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form  th:action="@{/login}" method="post">
    <input type="text" id="username" name="username"/>
    <input type="password" id="password" name="password"/>
    <input type="submit" value="提交"/>
</form>
</body>
</html>

9. 實(shí)現(xiàn)頁(yè)面權(quán)限

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

<head>
    <meta content="text/html;charset=UTF-8"/>
    <link rel="stylesheet" href="/css/bootstrap.min.css">
    <style type="text/css">
        body {
            padding-top: 50px;
        }
        .starter-template {
            padding: 40px 15px;
            text-align: center;
        }
    </style>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container">
        <div class="navbar-header">
            <a class="navbar-brand" href="#">Spring Security演示</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse">
            <ul class="nav navbar-nav">
                <li><a th:href="@{/}"> 首頁(yè) </a></li>
                <li><a th:href="@{/admin}"> admin </a></li>
            </ul>
        </div><!--/.nav-collapse -->
    </div>
</nav>


<div class="container">

    <div class="starter-template">
        <h1 th:text="${msg.title}"></h1>

        <p class="bg-primary" th:text="${msg.content}"></p>
        <div > <!-- 用戶類型為ROLE_ADMIN 顯示 -->
            <p class="bg-info" th:text="${msg.etraInfo}"></p>
        </div>

        <form th:action="@{/logout}" method="post">
            <input type="submit" class="btn btn-primary" value="注銷(xiāo)"/>
        </form>
    </div>

</div>
</body>
</html>

最后附上源碼連接:https://github.com/lhtGit/Spring-security-demo

結(jié)束語(yǔ)

至此Spring security就算是搭建完成肯尺,實(shí)現(xiàn)了基本權(quán)限的設(shè)置。但是還有一些問(wèn)題并沒(méi)與解決和實(shí)現(xiàn):

  1. 權(quán)限和角色沒(méi)有分開(kāi)躯枢,混合在了一起则吟,所以說(shuō)并沒(méi)有真正的實(shí)現(xiàn)角色和權(quán)限的管理
  2. 沒(méi)有實(shí)現(xiàn)驗(yàn)證碼部分
  3. 。锄蹂。氓仲。剛剛搭建,還沒(méi)有過(guò)多的感觸

2018-6-14 更新——加入驗(yàn)證碼

public class VerifyFilter extends OncePerRequestFilter {
    private static final PathMatcher pathMatcher = new AntPathMatcher();
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        if(isProtectedUrl(request)&&!validateVerify(request.getSession())){
            request.getRequestDispatcher("/login?Verify").forward(request,response);
        }else{
            filterChain.doFilter(request,response);
        }
    }

    //判斷驗(yàn)證碼是否已經(jīng)通過(guò)
    private boolean validateVerify(HttpSession session){
       return StringUtils.isEmpty(session.getAttribute(Common.verify))?false :(boolean) session.getAttribute(Common.verify);
    }

    // 攔截 /login的POST請(qǐng)求
    private boolean isProtectedUrl(HttpServletRequest request) {
        return  "POST".equals(request.getMethod()) && pathMatcher.match("/login", request.getServletPath());
    }
}

需要注意的是需要繼承OncePerRequestFilter 败匹,該類是所有security的filter的父類寨昙,
最后記得要在WebSecurityConfig的configure方法中加入這段話,才會(huì)起作用:

http.addFilterBefore(new VerifyFilter(),UsernamePasswordAuthenticationFilter.class);

該驗(yàn)證使用的是極限驗(yàn)證掀亩,不過(guò)是自己寫(xiě)的舔哪,整個(gè)驗(yàn)證的大概思路:

  1. 首先判斷是否已經(jīng)驗(yàn)證通過(guò)了(這個(gè)是極限驗(yàn)證部分的),如果通過(guò)了就在session中放一個(gè)布爾值槽棍,用以標(biāo)記
  2. 在VerifyFilter 過(guò)濾器中取出該標(biāo)記(一定要記得它在什么位置捉蚤,例如在login登錄頁(yè),只是在登錄時(shí)判斷炼七,那么就要判斷當(dāng)前的url是否是login缆巧,什么方式的(get/post),好讓程序能夠正確執(zhí)行)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末豌拙,一起剝皮案震驚了整個(gè)濱河市陕悬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌按傅,老刑警劉巖捉超,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異唯绍,居然都是意外死亡拼岳,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)况芒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)惜纸,“玉大人,你說(shuō)我怎么就攤上這事∧桶妫” “怎么了祠够?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)椭更。 經(jīng)常有香客問(wèn)我哪审,道長(zhǎng),這世上最難降的妖魔是什么虑瀑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮滴须,結(jié)果婚禮上舌狗,老公的妹妹穿的比我還像新娘。我一直安慰自己扔水,他們只是感情好痛侍,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著魔市,像睡著了一般主届。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上待德,一...
    開(kāi)封第一講書(shū)人閱讀 52,696評(píng)論 1 312
  • 那天君丁,我揣著相機(jī)與錄音,去河邊找鬼将宪。 笑死绘闷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的较坛。 我是一名探鬼主播印蔗,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼丑勤!你這毒婦竟也來(lái)了华嘹?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤法竞,失蹤者是張志新(化名)和其女友劉穎耙厚,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體爪喘,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡颜曾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了秉剑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泛豪。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出诡曙,到底是詐尸還是另有隱情臀叙,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布价卤,位于F島的核電站劝萤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏慎璧。R本人自食惡果不足惜床嫌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望胸私。 院中可真熱鬧厌处,春花似錦、人聲如沸岁疼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捷绒。三九已至瑰排,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間暖侨,已是汗流浹背椭住。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留它碎,地道東北人函荣。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像扳肛,于是被迫代替她去往敵國(guó)和親傻挂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理挖息,服務(wù)發(fā)現(xiàn)金拒,斷路器,智...
    卡卡羅2017閱讀 134,716評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,867評(píng)論 6 342
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架套腹,建立于...
    Hsinwong閱讀 22,442評(píng)論 1 92
  • 要加“m”說(shuō)明是MB绪抛,否則就是KB了. -Xms:初始值 -Xmx:最大值 -Xmn:最小值 java -Xms8...
    dadong0505閱讀 4,849評(píng)論 0 53
  • 最近又起了高調(diào)尖飞,哈哈症副。 想轉(zhuǎn)戰(zhàn)期刊……所以暫別簡(jiǎn)書(shū)店雅。 不過(guò),我會(huì)再回來(lái)贞铣。 在我不在的日子闹啦,請(qǐng)不要離開(kāi)我好么? 再回...
    橘子曼閱讀 428評(píng)論 7 6