搜索词>>spring mongodb 耗时0.0520
  • spring boot1.5.2整合spring data mongodb10.1

    Java编程中使用spring boot1.5.2框架整合spring data mongodb10.1,来使用mongodb数据库Java编程中使用spring boot1.5.2框架整合spring data mongodb10.1,来使用mongodb数据库<br /> <br /> 项目结构图:<br /> <img alt="项目结构图" class="img-thumbnail" src="/resources/assist/images/blog/e75e36b8-aabe-46f6-88c3-98ee6d3d8fa4.jpg" /><br /> 本项目主要讲解spring整合mongodb后的一些基本操作,如新增数据,修改数据,删除数据,查询数据<br /> <br /> 代码清单:<br /> <strong>定义一个简单的pojo Customer.java:</strong> <pre> <code class="language-java">package com.leftso.entity; /** * 测试用类 * * @author leftso * */ // @Document public class Customer { private String id; private String firstName; private String lastName; public Customer() { } public Customer(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } @Override public String toString() { return String.format("Customer[id=%s, firstName='%s', lastName='%s']", id, firstName, lastName); } } </code></pre> <br /> <strong>添加数据配置mongo.properties:</strong> <pre> <code>#DB host+port,Multiple host separation with ',' db.host=localhost:27017 #DB name db.name=test1 #DB User Name db.user= #DB User Password db.pwd=</code></pre> <br /> <strong>自定义配置mongodb的数据源<br /> 数据库配置文件MongoProperty.java:</strong> <pre> <code class="language-java">package com.leftso.config; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; /** * mongodb的配置文件载入 * * @author leftso * */ @Component @ConfigurationProperties(prefix = "db") @PropertySource("classpath:mongo.properties") public class MongoProperty { /** 主机地址IP+端口 **/ private String host; /** 数据库名称 ***/ private String name; /** 数据库用户(非必须) ***/ private String user; /** 数据库密码 **/ private String pwd; public String getHost() { return host; } public void setHost(String host) { this.host = host; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } } </code></pre> <br /> <strong>数据源MongoDBConfig.java:</strong> <pre> <code class="language-java">package com.leftso.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; import org.springframework.util.StringUtils; import com.mongodb.MongoClient; import com.mongodb.MongoClientURI; /** * mongodb 配置类 * * @author leftso * */ @Configuration public class MongoDBConfig { @Autowired MongoProperty mongoProperties; /** * 注入mongodb的工厂类 * * @return */ @Bean public MongoDbFactory mongoDbFactory() { // uri格式mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]] String mongoURI = "mongodb://" + mongoProperties.getHost(); if (!StringUtils.isEmpty(mongoProperties.getUser())) { mongoURI = "mongodb://" + mongoProperties.getUser() + ":" + mongoProperties.getPwd() + "@" + mongoProperties.getHost(); } // 为了方便实现mongodb多数据库和数据库的负债均衡这里使用url方式创建工厂 MongoClientURI mongoClientURI = new MongoClientURI(mongoURI); MongoClient mongoClient = new MongoClient(mongoClientURI); MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongoClient, mongoProperties.getName()); // 注意:以下构造函数已经弃用: // SimpleMongoDbFactory(com.mongodb.Mongo mongo, String databaseName); // 弃用版本1.7 // SimpleMongoDbFactory(com.mongodb.Mongo mongo, String databaseName, // UserCredentials credentials);弃用版本1.7 // SimpleMongoDbFactory(com.mongodb.Mongo mongo, String databaseName, // UserCredentials credentials, String // authenticationDatabaseName);弃用版本1.7 // SimpleMongoDbFactory(com.mongodb.MongoURI uri);弃用版本1.7 return mongoDbFactory; } /** * 获取操作实例 * * @param mongoDbFactory * @return */ @Bean public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory) { return new MongoTemplate(mongoDbFactory); } } </code></pre> <br /> <strong>创建customer的简单存储操作类<br /> 基于spring data框架的方式CustomerMongoRepository.java</strong><br />   <pre> <code class="language-java">package com.leftso.repository; import java.util.List; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; import com.leftso.entity.Customer; /** * spring data提供接口方式实现简单的操作,通常适合简单的或者测试用 * * @author leftso * */ @Repository public interface CustomerMongoRepository extends MongoRepository<Customer, String> { public Customer findByFirstName(String firstName); public List<Customer> findByLastName(String lastName); } </code></pre> <br /> <strong>自定义方式实现CustomizeCustomerMongoRepository.java</strong><br />   <pre> <code class="language-java">package com.leftso.repository; import java.util.List; import java.util.regex.Pattern; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Repository; import com.leftso.entity.Customer; /** * 自定义数据存储方式 * * @author leftso * */ @Repository public class CustomizeCustomerMongoRepository { @Autowired MongoTemplate mongoTemplate; /** * 保存一个对象 * * @return */ public Customer save(Customer customer) { mongoTemplate.save(customer); return customer; } /** * 删除所有 */ public void deleteAll() { mongoTemplate.dropCollection(Customer.class); } /** * 查询所有 * * @return */ public List<Customer> findAll() { return mongoTemplate.findAll(Customer.class); } /** * 精确查询 * * @param firstName * @return */ public List<Customer> findByFirstName(String firstName) { Query query = new Query(); query.addCriteria(Criteria.where("firstName").is(firstName)); return mongoTemplate.find(query, Customer.class); } /** * 模糊查询不区分大小写 * * @param lastName * @return */ public List<Customer> findByLastName(String lastName) { Query query = new Query(); Pattern pattern = Pattern.compile("^.*" + lastName + ".*$", Pattern.CASE_INSENSITIVE);// Pattern.CASE_INSENSITIVE不区分大小写 query.addCriteria(Criteria.where("lastName").regex(pattern)); return mongoTemplate.find(query, Customer.class); } } </code></pre> <br /> 项目源码下载:<br /> <a rel="nofollow" target="_blank" href="https://github.com/leftso/demo-spring-boot-mongodb">https://github.com/leftso/demo-spring-boot-mongodb</a><br />  
  • Spring data-mongodb ID自增长注解实现

    Spring data-mongodb ID自增长注解实现,mongodb ID自增长<h2>1.创建一个文档。类似一个序列的作用</h2> <pre> <code class="language-java">package com.leftso.autoid; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; /** * 系统自增长表id存放表 * * @author xq * */ @Document(collection = "sys_sequence") public class SequenceId { @Id private String id; @Field("seq_id") private long seqId; @Field("coll_name") private String collName; public String getId() { return id; } public void setId(String id) { this.id = id; } public long getSeqId() { return seqId; } public void setSeqId(long seqId) { this.seqId = seqId; } public String getCollName() { return collName; } public void setCollName(String collName) { this.collName = collName; } } </code></pre> <h2>2.创建一个自定义注解用于处理需要自增长的ID</h2> <pre> <code class="language-java">package com.leftso.autoid; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义自增长ID注解 * * @author xq * */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.FIELD }) public @interface AutoValue { } </code></pre> <h2><br /> 3.重写新增的监听事件</h2> <span style="color:#27ae60"><strong>注意:各大网站可能会有相似的代码。以下部分和spring data mongodb版本有关。下面代码中重写的public void onBeforeConvert(final Object source)方法在1.8版本开始就废弃了,不过官方推荐: Please use onBeforeConvert(BeforeConvertEvent),以下则为1.8以后版本的使用方法</strong></span> <pre> <code class="language-java">package com.leftso.autoid; import java.lang.reflect.Field; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.FindAndModifyOptions; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener; import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Component; import org.springframework.util.ReflectionUtils; @Component public class SaveEventListener extends AbstractMongoEventListener<Object> { @Autowired private MongoTemplate mongo; @Override public void onBeforeSave(BeforeSaveEvent<Object> event) { Object source = event.getSource(); if (source != null) { ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() { public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { ReflectionUtils.makeAccessible(field); // 如果字段添加了我们自定义的AutoValue注解 if (field.isAnnotationPresent(AutoValue.class) && field.get(source) instanceof Number && field.getLong(source) == 0) { // field.get(source) instanceof Number && // field.getLong(source)==0 // 判断注解的字段是否为number类型且值是否等于0.如果大于0说明有ID不需要生成ID // 设置自增ID field.set(source, getNextId(source.getClass().getSimpleName())); } } }); } } /** * 获取下一个自增ID * * @param collName * 集合(这里用类名,就唯一性来说最好还是存放长类名)名称 * @return 序列值 */ private Long getNextId(String collName) { Query query = new Query(Criteria.where("coll_name").is(collName)); Update update = new Update(); update.inc("seq_id", 1); FindAndModifyOptions options = new FindAndModifyOptions(); options.upsert(true); options.returnNew(true); SequenceId seq = mongo.findAndModify(query, update, options, SequenceId.class); return seq.getSeqId(); } } </code></pre> <h2><br /> 4.使用自定义注解完成ID自增长的实现</h2> <pre> <code class="language-java">package com.leftso.entity; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import com.leftso.autoid.AutoValue; @Document public class Student { @AutoValue @Id private long id; private String name; public Student(String name) { super(); this.name = name; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } </code></pre> <br />  
  • mongodb修改数据命令

    mongodb修改数据命令mongodb修改数据命令<br /> <br /> 1.切换至修改数据的数据库 <pre> <code class="language-sql">use your_dbname</code></pre> 2.修改数据 <pre> <code class="language-sql">db.blog.update({type:"programming"},{$set:{type:"coding"}}, { multi: true });</code></pre> 解释:<br /> db.table_name.update({匹配表达式},{$set:{新的值}}, { multi: true });最后一个是否修改匹配条件的所有,如果false则修改一条,默认false
  • Java MongoDB驱动程序

    Java MongoDB驱动程序,下载/升级,Java驱动程序兼容性,第三方框架和库<h1>Java MongoDB驱动程序</h1> <p>在这个页面上</p> <ul> <li><a href="https://docs.mongodb.com/ecosystem/drivers/java/#driver-features" id="id3" rel="nofollow" target="_blank">驱动程序特点</a></li> <li><a href="https://docs.mongodb.com/ecosystem/drivers/java/#download-upgrade" id="id4" rel="nofollow" target="_blank">下载/升级</a></li> <li><a href="https://docs.mongodb.com/ecosystem/drivers/java/#java-driver-compatibility" id="id5" rel="nofollow" target="_blank">Java驱动程序兼容性</a></li> <li><a href="https://docs.mongodb.com/ecosystem/drivers/java/#third-party-frameworks-and-libraries" id="id6" rel="nofollow" target="_blank">第三方框架和图书馆</a></li> <li><a href="https://docs.mongodb.com/ecosystem/drivers/java/#additional-resources" id="id7" rel="nofollow" target="_blank">其他资源</a></li> </ul> <p>从3.0版本开始,官方MongoDB Java驱动程序提供与MongoDB的同步和异步交互。有关官方MongoDB Java Driver参考资料,请参阅:</p> <ul> <li><a href="http://mongodb.github.io/mongo-java-driver/" rel="nofollow" target="_blank">MongoDB Java驱动程序文档</a></li> <li><a href="http://api.mongodb.com/java/current" rel="nofollow" target="_blank">MongoDB Java驱动程序API文档</a></li> </ul> <h2>驱动程序特性</h2> MongoDB驱动<br /> 一个更新的Java驱动程序,其中包括传统的API以及符合新的跨驱动程序CRUD规范的新的通用MongoCollection界面。有关Java驱动程序的文档,包括入门指南,请参阅<a href="http://mongodb.github.io/mongo-java-driver/3.2/driver/" rel="nofollow" target="_blank">Java驱动程序文档</a>。<br /> MongoDB异步驱动<br /> 一种新的异步API,可以利用Netty或Java 7的AsynchronousSocketChannel快速和非阻塞IO。有关Async Java驱动程序(包括入门指南)的<a href="http://mongodb.github.io/mongo-java-driver/3.2/driver-async/" rel="nofollow" target="_blank">文档</a>,请参阅<a href="http://mongodb.github.io/mongo-java-driver/3.2/driver-async/" rel="nofollow" target="_blank">Async Java驱动程序文档</a>。<br /> BSON图书馆<br /> 具有新型编解码器基础架构的独立BSON库,可用于构建高性能编码器和解码器,无需中间地图实例。有关BSON Library的文档,请参阅<a href="http://mongodb.github.io/mongo-java-driver/3.2/bson/" rel="nofollow" target="_blank">BSON Library</a>。<br /> 核心驱动<br /> 一个新的核心库,MongoDB驱动程序和异步驱动程序都在其上构建。用户可以使用新的核心库构建替代或实验高级API。 <h2>下载/升级</h2> <p>将驱动程序合并到项目中的推荐方法是使用依赖关系管理系统。有关更多信息,请参阅 <a href="http://mongodb.github.io/mongo-java-driver/" rel="nofollow" target="_blank">MongoDB Java驱动程序</a>。</p> <p>如果从较早版本的Java驱动程序升级,请参阅 <a href="http://mongodb.github.io/mongo-java-driver/3.2/whats-new/upgrading/" rel="nofollow" target="_blank">最新消息</a>。</p> <h2>Java驱动程序兼容性</h2> <h3>MongoDB兼容性</h3> <p>以下兼容性表格指定了与特定版本的MongoDB一起使用的MongoDB Java驱动程序的推荐版本。</p> <p>第一列列出了驱动程序版本。</p> <table border="1"> <thead> <tr> <th>Java驱动程序版本</th> <th>MongoDB 2.4</th> <th>MongoDB 2.6</th> <th>MongoDB 3.0</th> <th>MongoDB 3.2</th> <th>MongoDB 3.4</th> </tr> </thead> <tbody> <tr> <th>版本3.4</th> <td>✓</td> <td>✓</td> <td>✓</td> <td>✓</td> <td>✓</td> </tr> <tr> <th>版本3.3</th> <td>✓</td> <td>✓</td> <td>✓</td> <td>✓</td> <td> </td> </tr> <tr> <th>版本3.2</th> <td>✓</td> <td>✓</td> <td>✓</td> <td>✓</td> <td> </td> </tr> <tr> <th>版本2.14</th> <td>✓</td> <td>✓</td> <td>✓</td> <td>✓<a href="https://docs.mongodb.com/ecosystem/drivers/java/#id2" id="id1" rel="nofollow">[*]</a></td> <td> </td> </tr> </tbody> </table> <p>有关其他驱动程序版本,请参阅<a href="https://docs.mongodb.com/ecosystem/drivers/driver-compatibility-reference/#reference-compatibility-mongodb-java" rel="nofollow" target="_blank">Java驱动程序MongoDB兼容性参考</a>。</p> <p>该驱动程序不支持旧版本的MongoDB。</p> <table id="id2"> <tbody> <tr> <td><a href="https://docs.mongodb.com/ecosystem/drivers/java/#id1" rel="nofollow" target="_blank">[*]</a></td> <td>2.14驱动程序不支持所有MongoDB 3.2功能(例如,阅读关注); 但是,如果您当前使用的是2.x版本的驱动程序,并且希望针对MongoDB 3.2运行,但无法升级到驱动程序版本3.2,请使用2.14驱动程序。</td> </tr> </tbody> </table> <h3>语言兼容性</h3> <p>以下兼容性表格指定了与特定版本的Java一起使用的MongoDB Java驱动程序的推荐版本。</p> <p>第一列列出了驱动程序版本。</p> <table border="1"> <thead> <tr> <th>Java驱动程序版本</th> <th>Java 5</th> <th>Java 6</th> <th>Java 7</th> <th>Java 8</th> </tr> </thead> <tbody> <tr> <th>版本3.x</th> <td> </td> <td>✓</td> <td>✓</td> <td>✓</td> </tr> <tr> <th>版本2.x</th> <td>✓</td> <td>✓</td> <td>✓</td> <td>✓</td> </tr> </tbody> </table> <p>有关其他驱动程序版本,请参阅<a href="https://docs.mongodb.com/ecosystem/drivers/driver-compatibility-reference/#reference-compatibility-language-java" rel="nofollow" target="_blank">Java驱动程序语言兼容性参考</a>。</p> <h2>第三方框架和库</h2> <h3>POJO贴片</h3> <ul> <li><a href="https://github.com/mongodb/morphia" rel="nofollow" target="_blank">Morphia</a>。带有DAO / Datastore抽象的Type-Safe Wrapper。</li> <li><a href="http://www.springsource.org/spring-data/mongodb" rel="nofollow" target="_blank">Spring MongoDB</a>。为Spring用户提供熟悉的数据访问功能,包括丰富的POJO映射。</li> <li><a href="http://sboesebeck.github.io/morphium/" rel="nofollow" target="_blank">形态</a>。功能丰富的POJO Mapper包括声明缓存,集群感知,验证,部分更新等功能,支持聚合框架。</li> <li><a href="http://github.com/jannehietamaki/mungbean" rel="nofollow" target="_blank">绿豆</a>(w / clojure支持)。</li> <li><a href="http://www.datanucleus.org/products/accessplatform_3_0/mongodb/support.html" rel="nofollow" target="_blank">DataNucleus JPA / JDO</a>。JPA / JDO包装器</li> <li><a href="https://github.com/dadastream/lib-mongomapper" rel="nofollow" target="_blank">LIB-mongomapper</a>。JavaBean Mapper(无注释)。</li> <li><a href="http://mongojack.org/" rel="nofollow" target="_blank">MongoJack</a>。使用杰克逊(注释)来映射到POJO或从POJO映射,并有一个简单的包装<code>DBCollection</code>。</li> <li><a href="http://kundera.googlecode.com/" rel="nofollow" target="_blank">昆德拉</a>。JPA兼容ORM。适用于多个数据存储。</li> <li><a href="http://dbuschman7.github.io/mongoFS/" rel="nofollow" target="_blank">MongoFS</a>。增强的文件存储库,支持文件压缩,加密和Zip文件扩展。可以在GridFS兼容的桶上使用。</li> <li><a href="http://www.jongo.org/" rel="nofollow" target="_blank">琼戈</a>。在Java中查询<code>mongo</code>(在shell中使用字符串),将结果解组成Java对象(使用Jackson)</li> <li><a href="http://mongolink.org/" rel="nofollow" target="_blank">MongoLink</a>。对象文档映射器(ODM。)使用简单的java DSL进行映射声明。</li> <li><a href="http://www.hibernate.org/ogm/" rel="nofollow" target="_blank">休眠OGM</a>。为MongoDB提供Java持久性支持。</li> <li><a href="http://github.com/ParaPenguin/morphix" rel="nofollow" target="_blank">Morphix</a>。轻量级,易于使用的POJO映射器,具有对象缓存和生命周期方法。</li> </ul> <h3>代码生成</h3> <ul> <li><a href="http://java.dzone.com/articles/using-mongodb-sculptor" rel="nofollow" target="_blank">雕塑家</a>。基于MongoDB的DSL - > Java(代码生成器)</li> <li><a href="http://github.com/mattinsler/com.lowereast.guiceymongo/" rel="nofollow" target="_blank">GuicyData</a>。DSL - > Java生成器与Guice集成。</li> </ul> <h3>杂项</h3> <ul> <li><a href="https://github.com/gaillard/mongo-queue-java" rel="nofollow" target="_blank">mongo-queue-java</a>。Java消息队列使用MongoDB作为后端。</li> <li><a href="https://github.com/deftlabs/mongo-java-logging" rel="nofollow" target="_blank">mongo-java-logging</a>。Java日志记录处理程序。</li> <li><a href="http://code.google.com/p/log4mongo/" rel="nofollow" target="_blank">log4mongo</a>。一个log4j appender</li> <li><a href="http://www.allanbank.com/mongodb-async-driver/" rel="nofollow" target="_blank">Allanbank异步Java驱动程序</a></li> <li><a href="http://www.unityjdbc.com/mongojdbc/" rel="nofollow" target="_blank">MongoDB的JDBC驱动</a></li> <li><a href="http://github.com/erh/mongo-jdbc" rel="nofollow" target="_blank">(实验,Type4)JDBC驱动程序</a></li> <li><a href="http://metamodel.eobjects.org/download.html" rel="nofollow" target="_blank">元模型数据挖掘和查询库</a></li> <li><a href="https://sites.google.com/site/mongodbjavarestserver/home" rel="nofollow" target="_blank">Mongodb Java REST服务器</a>基于<a href="http://www.eclipse.org/jetty/" rel="nofollow" target="_blank">Jetty</a></li> </ul> <h3>Clojure的</h3> <ul> <li><a href="https://github.com/michaelklishin/monger" rel="nofollow" target="_blank">贩子</a></li> <li><a href="https://github.com/aboekhoff/congomongo" rel="nofollow" target="_blank">刚果蒙古</a></li> </ul> <h3>Groovy的</h3> <ul> <li><a href="http://github.com/poiati/gmongo" rel="nofollow" target="_blank">GMongo,一个Groovy包装到MongoDB Java驱动程序</a></li> <li><a href="http://blog.paulopoiati.com/2010/06/20/gmongo-0-5-released" rel="nofollow" target="_blank">GMongo 0.5发行编写</a></li> </ul> <h3>JavaScript(Rhino)</h3> <ul> <li><a href="https://github.com/nlloyd/horn-of-mongo" rel="nofollow" target="_blank">蒙戈的号角</a>。一个基于Java的Rhino JavaScript Engine构建的MongoDB shell。</li> <li><a href="http://code.google.com/p/mongodb-rhino" rel="nofollow" target="_blank">MongoDB犀牛</a>。提供JVM和MongoDB的Rhino JavaScript引擎之间的完全集成的工具集。使用MongoDB Java驱动程序。</li> </ul> <h3>Hadoop的</h3> <p><a href="https://docs.mongodb.com/ecosystem/tools/hadoop/#hadoop-connector" rel="nofollow" target="_blank">MongoDB Connector for Hadoop</a></p> <h2>其他资源</h2> <ul> <li><a href="https://university.mongodb.com/courses/M101J/about?jmp=docs" rel="nofollow" target="_blank">M101J:MongoDB for Java开发者免费在线课程</a></li> <li><a href="http://www.mongodb.com/presentations/webinar-mongodb-java-everything-you-need-know?jmp=docs" rel="nofollow" target="_blank">演示:MongoDB + Java - 你需要知道的一切</a></li> <li><a href="http://docs.mongodb.org/getting-started/java" rel="nofollow" target="_blank">MongoDB入门(Java Edition)</a></li> </ul>
  • mongodb数据库备份/恢复

    mongodb数据库备份(mongodump)/恢复(mongorestore)mongodb数据库备份(mongodump)/恢复(mongorestore) <h4>1.备份</h4> 命令: <pre> <code># ./mongodump -h your_host --port your_port -d your_db_name -u=your_db_user -p=your_db_password -o dir_to_save_backup</code></pre> <strong>执行过程...:<br /> <img alt="备份过程" class="img-thumbnail" src="/resources/assist/images/blog/fda64c87-17fc-49b0-a462-4f7568dde149.png" style="height:214px; width:619px" /></strong><br /> 参数说明:<br /> <strong>-h 指定数据库主机地址/IP<br /> --port 指定数据库使用端口,默认27017<br /> -d 指定备份数据库名称<br /> -u 指定数据库用户名称(如果数据库未启用用户验证则忽略该参数,如果启用权限确保该用户有权限)<br /> -p 指定数据库用户密码(如果数据库未启用用户验证则忽略该参数)<br /> -o 指定备份的文件所存放的目录,该目录需提前创建</strong> <h4>2.恢复</h4> 命令: <pre> <code>#mongorestore -h localhost:27017 -d your_db_name -u=your_user_name -p=your_password --dir path_to_backup</code></pre> 参数说明:<br /> <strong>-h 指定数据库地址及端口<br /> -d 指定数据库名称<br /> -u 指定数据库用户名(如果数据库未启用用户验证则忽略该参数,如果启用权限确保该用户有权限)<br /> -p 指定数据库用户密码(如果数据库未启用用户验证则忽略该参数)<br /> --dir 指定数据库备份的目录</strong>
  • mongodb数据库linux安装配置用户创建删除修改

    mongodb数据库linux安装配置用户创建删除修改1.下载mongodb压缩包<br /> 地址:https://www.mongodb.com/download-center?jmp=nav#community<br /> 或者: https://www.mongodb.org/dl/linux/x86_64-amazon?_ga=1.227669659.765724145.1480085547<br /> 2. 文件上传<br /> 上传mongodb文件包到Linux系统<br /> 也可选择使用命令<br /> #wget 详细地址…<br /> 3. 文件解压<br /> 解压文 <pre> <code>#tar –xvf  文件名</code></pre> <br /> 移动文件夹到/usr/local目录下(也可根据自己爱好) <pre> <code>#mv 文件名 /user/mongodb </code></pre> <br /> <strong>创建相关文件目录</strong><br /> #mv 文件名 /user/mongodb创建数据存放目录/usr/local/mogodb/data <pre> <code>#mkdir –p /usr/local/mogodb/data</code></pre> 创建日志存放目录/user/local/mongodb/logs <pre> <code class="language-bash">#mkdir –p /usr/local/mongodb/logs</code></pre> 创建配置文件存放路径/usr/local/mongodb/conf <pre> <code>#mkdir –p /usr/local/mongodb/conf</code></pre> <ul> <li>创建配置文件mongodb.conf</li> <li>vi /usr/local/mongodb/conf/mongodb.conf</li> </ul> <pre> <code>#vi /usr/local/mongodb/conf/mongodb.conf</code></pre>   <ul> <li>:内容</li> </ul> <pre> <code>dbpath = /usr/local/mongodb/data #数据文件存放目录 logpath = /usr/local/mongodb/logs/mongodb.log #日志文件存放目录 port = 27017#端口 fork = true#以守护程序的方式启用,即在后台运行 nohttpinterface = true</code></pre> <br /> <img alt="配置文件内容" class="img-thumbnail" src="/resources/assist/images/blog/e7a875d6-2d04-4ff1-8ed1-9a8fc275e365.png" style="height:126px; width:491px" title="配置文件内容" /> <ul> <li>启动mongodb(无需用户登录权限的启动方式)</li> </ul> <pre> <code class="language-bash">#/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/conf/mongodb.conf</code></pre> <img alt="启动数据库" class="img-thumbnail" src="/resources/assist/images/blog/b4bb43d6-71f1-483e-a3b4-46cd6ba43af1.png" style="height:154px; width:786px" title="启动数据库" /> <ul> <li>进入mongodb</li> <li>[root@MiWiFi-R1CM-srv bin]# ./mongo</li> </ul> <img alt="登录数据库" class="img-thumbnail" src="/resources/assist/images/blog/2636a0ce-1150-4b79-a548-fe6ca70b1fe3.png" style="height:255px; width:982px" title="登录数据库" /> <ol> <li>创建数据库用户</li> <li>mongo shell</li> <li>切换到需要创建用户的数据库</li> </ol> <pre> <code>>use admin</code></pre>   <ul> <li>创建用户并赋予角色</li> </ul> <pre> <code>> db.createUser({user:'root',pwd:'root',roles:[{ role:'root',db: 'admin'}]})</code></pre> <br /> <br /> <img alt="mongodb数据库用户创建" class="img-thumbnail" src="/resources/assist/images/blog/9dbfe29f-a7c5-4e3f-81c3-5ac43c8de54e.png" style="height:134px; width:990px" title="mongodb数据库用户创建" /> <ul> <li> </li> </ul> <em>1. </em><em>数据库用户角色:read</em><em>、readWrite;</em><br /> <em>2. </em><em>数据库管理角色:dbAdmin</em><em>、dbOwner</em><em>、userAdmin</em><em>;</em><br /> <em>3. </em><em>集群管理角色:clusterAdmin</em><em>、clusterManager</em><em>、clusterMonitor</em><em>、hostManager</em><em>;</em><br /> <em>4. </em><em>备份恢复角色:backup</em><em>、restore</em><em>;</em><br /> <em>5. </em><em>所有数据库角色:readAnyDatabase</em><em>、readWriteAnyDatabase</em><em>、userAdminAnyDatabase</em><em>、dbAdminAnyDatabase</em><br /> <em>6. </em><em>超级用户角色:root</em><br /> <em>// </em><em>这里还有几个角色间接或直接提供了系统超级用户的访问(dbOwner </em><em>、userAdmin</em><em>、userAdminAnyDatabase</em><em>)</em><br /> <em>7. </em><em>内部角色:__system</em><br />   <ol style="list-style-type:square"> <li>查看刚才创建的用户</li> </ol> <pre> <code>db.system.users.find();</code></pre> <br /> <img alt="查询用户" class="img-thumbnail" src="/resources/assist/images/blog/269a1e61-3134-4716-b4c4-8bbe2be12987.png" style="height:179px; width:878px" title="查询用户" /> <ul> <li>关闭mongodb,修改配置文件,启用安全登录</li> </ul> 编辑配置文件mongodb.conf<br /> 新增最后一行:<br /> auth = true #表示启用用户权限登录<br /> <img alt="启用用户登录" class="img-thumbnail" src="/resources/assist/images/blog/e7c07695-5b74-4b72-ae03-fac59e7facff.png" style="height:149px; width:550px" title="启用用户登录" /><br /> 编辑完成后启动mongodb服务<br /> # /usr/local/mongodb/bin/mongod --config /usr/local/mongodb/conf/mongodb.conf <ul> <li>登录用户</li> </ul> 启用用户登录操作后默认进去再次使用查看命令将提示无权限<br /> <img alt="不用用户登录,且使用数据库查询命令" class="img-thumbnail" src="/resources/assist/images/blog/a66d274c-393e-4edb-b8bb-6968bdf25c81.png" style="height:261px; width:615px" /><br /> 用户切换至自己的数据库并登录(说明:mongodb用户都是在那个库创建即为那个库的用户,登录也需要到对应的数据库)<br /> 登陆用户,再使用查询数据库命令<br /> <img alt="登陆用户,再使用查询数据库命令" class="img-thumbnail" src="/resources/assist/images/blog/038f9ef7-acfe-4235-bb51-c79ac2515ce1.png" style="height:188px; width:252px" title="登陆用户,再使用查询数据库命令" /><br /> 登录后返回1表示成功,登录后将有权限操作数据库相关命令 <ul> <li>修改用户密码</li> </ul> 用户登录后执行: <pre> <code>> db.changeUserPassword('root','root123');</code></pre> <br /> 退出后再次用之前的密码,将提示失败<br /> <img alt="推出后再次用之前的密码,将提示失败" class="img-thumbnail" src="/resources/assist/images/blog/c4724ea4-84a7-49f8-8f4d-c5d8cfcd1efc.png" style="height:71px; width:236px" title="推出后再次用之前的密码,将提示失败" /><br /> 使用修改后的密码成功登录<br /> <img alt="" class="img-thumbnail" src="/resources/assist/images/blog/43165636-4af1-4e7e-9f2d-8555ddc5e15a.png" style="height:66px; width:255px" /><br /> 返回1表示登陆成功 <ul> <li>删除创建的用户(启用的无权限启动模式)</li> </ul> <pre> <code>> db.dropUser('root');</code></pre> <br /> 执行命令后返回 true 表示成功删除 <pre> <code>db.system.users.find();</code></pre> <br /> 再次查询将无用户<br /> <br /> <br /> <br /> <br /> MongoDB主从配置手记: <pre> <code class="language-html">vi /etc/yum.repos.d/mongodb-org-3.4.repo [mongodb-org-3.4] name=MongoDB 3.4 Repository baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/ gpgcheck=0 enabled=1 yum install -y mongodb-org 新建dbpath=/opt/mongodb/db/ logpath=/opt/mongodb/logs/文件夹 /usr/bin/mongod 启动地址 /etc/mongod.conf 配置文件地址 netstat -nltp|grep mongod 查看端口 mongodb1 mongod --config /etc/mongod.conf --source 192.168.3.11:8203 --noauth /usr/bin/mongod --dbpath=/opt/mongodb/db/ --logpath=/opt/mongodb/logs/mongodb.log --master --slave --source 192.168.3.11:8203 --bind_ip=0.0.0.0 --maxConns=20000 --fork --directoryperdb --noauth mongodb2 mongod --config /etc/mongod.conf --source 192.168.3.11:8201 --noauth /usr/bin/mongod --dbpath=/opt/mongodb/db/ --logpath=/opt/mongodb/logs/mongodb.log --master --slave --source 192.168.3.11:8201 --bind_ip=0.0.0.0 --maxConns=20000 --fork --directoryperdb --noauth 进入MongoDB控制台 db.shutdownServer()方式 # mongo 进入本机 如果要进去其他机器加入 localhost:27000 > use admin > db.shutdownServer()</code></pre> <br /> <br />  
  • MongoDB索引策略和索引类型详解

    MongoDB索引策略和索引类型说明MongoDB索引策略和索引类型说明
  • Spring WebFlux 和Reactive MongoDB来构建Reactive Rest API

    Spring WebFlux 和Reactive MongoDB来构建Reactive Rest API,Spring 5通过引入一种名为Spring WebFlux的全新响应式框架来支持反应式编程范例。<h2>1.引言</h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">Spring 5通过引入一种名为<strong>Spring WebFlux的</strong>全新反应框架来支持响应式编程范例。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">Spring WebFlux是一个自下而上的异步框架。它可以使用Servlet 3.1非阻塞IO API以及其他异步运行时环境(如netty或undertow)在Servlet容器上运行。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">它可以与Spring MVC一起使用。是的,Spring MVC不会去任何地方。这是一个开发人员长期以来使用的流行的Web框架。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">但是你现在可以在新的反应框架和传统的Spring MVC之间做出选择。您可以根据自己的使用情况选择使用它们中的任何一个。</span></span></span><br /> <br />  </p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">Spring WebFlux使用一个名为Reactor的库作为响应支持。Reactor是<a href="https://github.com/reactive-streams/reactive-streams-jvm#reactive-streams" rel="external nofollow" style="box-sizing:border-box; color:#419be8; text-decoration:none; word-wrap:break-word" target="_blank" >Reactive Streams</a>规范的一个实现。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">Reactor提供两种主要的类型,称为<code>Flux</code>和<code>Mono</code>。这两种类型都实现了<code>Publisher</code>Reactive Streams提供的接口。<code>Flux</code>用于表示0..N个元素的流,<code>Mono</code>用于表示0..1个元素的流。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">虽然Spring使用Reactor作为其大部分内部API的核心依赖,但它也支持在应用程序级别使用RxJava。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"> </p> <h2 style="margin-left:0px; margin-right:0px; text-align:start">2.Spring WebFlux支持的编程模型</h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">Spring WebFlux支持两种类型的编程模型:</span></span></span></p> <ol> <li>带有<code>@Controller</code>,<code>@RequestMapping</code>和其他注释的基于注释的传统模型,您在Spring MVC中一直使用。</li> <li>基于Java 8 lambda表达式的全新功能样式模型,用于路由和处理请求。</li> </ol> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">在本文中,我们将使用传统的基于注释的编程模型。我将在未来的文章中撰写功能风格模型。</span></span></span></p> <h2 style="margin-left:0px; margin-right:0px; text-align:start"><br /> 3.让我们在Spring Boot中构建一个Reactive Restful服务</h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">在本文中,我们将为迷你Twitter应用程序构建一个Restful API。该应用程序将只有一个称为的域模型<code>Tweet</code>。每个<code>Tweet</code>人都有<code>text</code>一个<code>createdAt</code>领域。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">我们将使用MongoDB作为我们的数据存储以及反应型mongodb驱动程序。我们将构建用于创建,检索,更新和删除Tweet的REST API。所有的REST API都是异步的,并且会返回一个发布者。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">我们还将学习如何将数据从数据库传输到客户端。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">最后,我们将编写集成测试以使用Spring 5提供的新异步WebTestClient测试所有API。</span></span></span></p> <h2 style="margin-left:0px; margin-right:0px; text-align:start">4.创建项目</h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">我们使用Spring Initializr Web应用程序来生成我们的应用程序。按照以下步骤生成项目 -</span></span></span></p> <ol> <li>转到<a href="http://start.spring.io/" rel="external nofollow" style="box-sizing:border-box; color:#419be8; text-decoration:none; word-wrap:break-word" target="_blank" >http://start.spring.io</a></li> <li>选择Spring Boot版本<strong>2.x</strong></li> <li>输入工件的值作为<strong>webflux-demo</strong></li> <li>添加<strong>Reactive Web</strong>和<strong>Reactive MongoDB</strong>依赖项</li> <li>点击<strong>生成项目</strong>生成并下载项目。</li> </ol> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff"><img srcset="" width="" size="" class="img-thumbnail" alt="spring官网生成项目" src="/resources/assist/images/blog/bc7bae06bc4c4868a7df2ed2f49828c8.png" /></span></span></span><br /> 下载项目后,将其解压缩并导入到您最喜欢的IDE中。该项目的目录结构应该如下所示 -<br /> <span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff"><img srcset="" width="" size="" class="img-thumbnail" alt="导入spring 官网生成的maven项目" src="/resources/assist/images/blog/94b74bcde26549c2a0f52a246f54b2e5.png" /></span></span></span></p> <h2 style="margin-left:0px; margin-right:0px; text-align:start">配置MongoDB</h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">您可以通过简单地将以下属性添加到<code>application.properties</code>文件来配置MongoDB -</span></span></span></p> <pre> <code class="language-html">spring.data.mongodb.uri=mongodb://localhost:27017/webflux_demo</code></pre> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">Spring Boot将在启动时读取此配置并自动配置数据源。</span></span></span></p> <h2 style="margin-left:0px; margin-right:0px; text-align:start">创建领域模型</h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">让我们创建我们的领域模型 - <code>Tweet</code>。创建一个名为<code>model</code>inside <code>com.example.webfluxdemo</code>package 的新包,然后创建一个名为<code>Tweet.java</code>以下内容的文件-</span></span></span></p> <pre> <code class="language-java">import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.util.Date; @Document(collection = "tweets") public class Tweet { @Id private String id; @NotBlank @Size(max = 140) private String text; @NotNull private Date createdAt = new Date(); public Tweet() { } public Tweet(String text) { this.id = id; this.text = text; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getText() { return text; } public void setText(String text) { this.text = text; } public Date getCreatedAt() { return createdAt; } public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } }</code></pre> <p style="margin-left:0px; margin-right:0px; text-align:start">够简单!Tweet模型包含一个<code>text</code>和一个<code>createdAt</code>字段。该<code>text</code>字段用注释<code>@NotBlank</code>和<code>@Size</code>注释确保它不是空白并且最多有140个字符。<br /> <br />  </p> <h2 style="margin-left:0px; margin-right:0px; text-align:start">5.创建存储库</h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">接下来,我们将创建将用于访问MongoDB数据库的数据访问层。创建一个名为<code>repository</code>inside 的新包<code>com.example.webfluxdemo</code>,然后<code>TweetRepository.java</code>使用以下内容创建一个新文件-</span></span></span></p> <pre> <code class="language-java">import com.example.webfluxdemo.model.Tweet; import org.springframework.data.mongodb.repository.ReactiveMongoRepository; import org.springframework.stereotype.Repository; @Repository public interface TweetRepository extends ReactiveMongoRepository<Tweet, String> { }</code></pre> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">该<code>TweetRepository</code>接口扩展<a href="https://docs.spring.io/spring-data/mongodb/docs/2.0.0.RC2/api/org/springframework/data/mongodb/repository/ReactiveMongoRepository.html" rel="external nofollow" style="box-sizing:border-box; color:#419be8; text-decoration:none; word-wrap:break-word" target="_blank" ><code>ReactiveMongoRepository</code></a>了文档中的各种CRUD方法。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">Spring Boot自动插入在<a href="https://docs.spring.io/spring-data/mongodb/docs/2.0.0.RC2/api/org/springframework/data/mongodb/repository/support/SimpleReactiveMongoRepository.html" rel="external nofollow" style="box-sizing:border-box; color:#419be8; text-decoration:none; word-wrap:break-word" target="_blank" ><code>SimpleReactiveMongoRepository</code></a>运行时调用的此接口的实现。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">因此,您无需编写任何代码就可以轻松获取文档上的所有CRUD方法。以下是一些可用的方法<code>SimpleReactiveMongoRepository</code>-</span></span></span></p> <pre> <code class="language-java">reactor.core.publisher.Flux<T> findAll(); reactor.core.publisher.Mono<T> findById(ID id); <S extends T> reactor.core.publisher.Mono<S> save(S entity); reactor.core.publisher.Mono<Void> delete(T entity);</code></pre> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">请注意,所有方法都是异步的,并以a <code>Flux</code>或<code>Mono</code>类型的形式返回发布者。</span></span></span></p> <h2 style="margin-left:0px; margin-right:0px; text-align:start">创建控制器端点</h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">最后,让我们编写将暴露给客户端的API。创建一个名为<code>controller</code>inside 的新包<code>com.example.webfluxdemo</code>,然后<code>TweetController.java</code>使用以下内容创建一个新文件-</span></span></span><br />  </p> <pre> <code class="language-java">import com.example.webfluxdemo.model.Tweet; import com.example.webfluxdemo.repository.TweetRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import javax.validation.Valid; @RestController public class TweetController { @Autowired private TweetRepository tweetRepository; @GetMapping("/tweets") public Flux<Tweet> getAllTweets() { return tweetRepository.findAll(); } @PostMapping("/tweets") public Mono<Tweet> createTweets(@Valid @RequestBody Tweet tweet) { return tweetRepository.save(tweet); } @GetMapping("/tweets/{id}") public Mono<ResponseEntity<Tweet>> getTweetById(@PathVariable(value = "id") String tweetId) { return tweetRepository.findById(tweetId) .map(savedTweet -> ResponseEntity.ok(savedTweet)) .defaultIfEmpty(ResponseEntity.notFound().build()); } @PutMapping("/tweets/{id}") public Mono<ResponseEntity<Tweet>> updateTweet(@PathVariable(value = "id") String tweetId, @Valid @RequestBody Tweet tweet) { return tweetRepository.findById(tweetId) .flatMap(existingTweet -> { existingTweet.setText(tweet.getText()); return tweetRepository.save(existingTweet); }) .map(updatedTweet -> new ResponseEntity<>(updatedTweet, HttpStatus.OK)) .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND)); } @DeleteMapping("/tweets/{id}") public Mono<ResponseEntity<Void>> deleteTweet(@PathVariable(value = "id") String tweetId) { return tweetRepository.findById(tweetId) .flatMap(existingTweet -> tweetRepository.delete(existingTweet) .then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK))) ) .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND)); } // Tweets are Sent to the client as Server Sent Events @GetMapping(value = "/stream/tweets", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<Tweet> streamAllTweets() { return tweetRepository.findAll(); } }</code></pre> <p style="margin-left:0px; margin-right:0px; text-align:start">所有的控制器端点都以Flux或Mono的形式返回一个Publisher。我们将内容类型设置为的最后一个端点非常有趣<code>text/event-stream</code>。它以<strong><a href="https://en.wikipedia.org/wiki/Server-sent_events" rel="external nofollow" style="box-sizing:border-box; color:#419be8; text-decoration:none; word-wrap:break-word" target="_blank" >服务器发送事件</a></strong>的形式将推文<strong><a href="https://en.wikipedia.org/wiki/Server-sent_events" rel="external nofollow" style="box-sizing:border-box; color:#419be8; text-decoration:none; word-wrap:break-word" target="_blank" >发送</a></strong>到像这样的浏览器 -</p> <pre> <code class="language-json">data: {"id":"59ba5389d2b2a85ed4ebdafa","text":"tweet1","createdAt":1505383305602} data: {"id":"59ba5587d2b2a85f93b8ece7","text":"tweet2","createdAt":1505383814847}</code></pre> <p style="margin-left:0px; margin-right:0px; text-align:start">现在我们正在讨论事件流,您可能会问以下端点是否也返回一个Stream?</p> <pre> <code class="language-java">@GetMapping("/tweets") public Flux<Tweet> getAllTweets() { return tweetRepository.findAll(); }</code></pre> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">答案是肯定的。<code>Flux<Tweet></code>代表推文流。但是,默认情况下,它将生成一个JSON数组,因为如果将单个JSON对象流发送给浏览器,那么它将不会是一个有效的JSON文档。除了使用Server-Sent-Events或WebSocket之外,浏览器客户端无法使用流。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">但是,非浏览器客户端可以通过设置<code>Accept</code>标头来请求JSON流<code>application/stream+json</code>,并且响应将是类似于Server-Sent-Events的JSON流,但不需要额外的格式:</span></span></span></p> <pre> <code class="language-json">{"id":"59ba5389d2b2a85ed4ebdafa","text":"tweet1","createdAt":1505383305602} {"id":"59ba5587d2b2a85f93b8ece7","text":"tweet2","createdAt":1505383814847}</code></pre> <h2 style="margin-left:0px; margin-right:0px; text-align:start">使用WebTestClient进行集成测试</h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">Spring 5还提供了一个异步和被动的http客户端,<code>WebClient</code>用于处理异步和流式API。这是一个被动的选择<code>RestTemplate</code>。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">此外,你还可以得到一个<code>WebTestClient</code>写作集成测试。测试客户端可以运行在实时服务器上,也可以用于模拟请求和响应。</span></span></span></p> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">我们将使用WebTestClient为我们的REST API编写集成测试。打开<code>WebfluxDemoApplicationTests.java</code>文件并将以下测试添加到它 -</span></span></span></p> <pre> <code class="language-java">import com.example.webfluxdemo.model.Tweet; import com.example.webfluxdemo.repository.TweetRepository; import org.assertj.core.api.Assertions; 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.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; import reactor.core.publisher.Mono; import java.util.Collections; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class WebfluxDemoApplicationTests { @Autowired private WebTestClient webTestClient; @Autowired TweetRepository tweetRepository; @Test public void testCreateTweet() { Tweet tweet = new Tweet("This is a Test Tweet"); webTestClient.post().uri("/tweets") .contentType(MediaType.APPLICATION_JSON_UTF8) .accept(MediaType.APPLICATION_JSON_UTF8) .body(Mono.just(tweet), Tweet.class) .exchange() .expectStatus().isOk() .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8) .expectBody() .jsonPath("$.id").isNotEmpty() .jsonPath("$.text").isEqualTo("This is a Test Tweet"); } @Test public void testGetAllTweets() { webTestClient.get().uri("/tweets") .accept(MediaType.APPLICATION_JSON_UTF8) .exchange() .expectStatus().isOk() .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8) .expectBodyList(Tweet.class); } @Test public void testGetSingleTweet() { Tweet tweet = tweetRepository.save(new Tweet("Hello, World!")).block(); webTestClient.get() .uri("/tweets/{id}", Collections.singletonMap("id", tweet.getId())) .exchange() .expectStatus().isOk() .expectBody() .consumeWith(response -> Assertions.assertThat(response.getResponseBody()).isNotNull()); } @Test public void testUpdateTweet() { Tweet tweet = tweetRepository.save(new Tweet("Initial Tweet")).block(); Tweet newTweetData = new Tweet("Updated Tweet"); webTestClient.put() .uri("/tweets/{id}", Collections.singletonMap("id", tweet.getId())) .contentType(MediaType.APPLICATION_JSON_UTF8) .accept(MediaType.APPLICATION_JSON_UTF8) .body(Mono.just(newTweetData), Tweet.class) .exchange() .expectStatus().isOk() .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8) .expectBody() .jsonPath("$.text").isEqualTo("Updated Tweet"); } @Test public void testDeleteTweet() { Tweet tweet = tweetRepository.save(new Tweet("To be deleted")).block(); webTestClient.delete() .uri("/tweets/{id}", Collections.singletonMap("id", tweet.getId())) .exchange() .expectStatus().isOk(); } }</code></pre> <p style="margin-left:0px; margin-right:0px; text-align:start">在上面的例子中,我为所有的CRUD API编写了测试。您可以通过转到项目的根目录并键入来运行测试<code>mvn test</code>。<br />  </p> <h2 style="margin-left:0px; margin-right:0px; text-align:start">6.总结</h2> <p style="margin-left:0px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">在本文中,我们学习了使用Spring进行反应式编程的基础知识,并使用Spring WebFlux框架提供的反应式支持构建了一个简单的Restful服务。我们还使用WebTestClient测试了所有Rest API。</span></span></span></p> <blockquote> <p style="margin-left:40px; margin-right:0px; text-align:start"><span style="color:rgba(0, 0, 0, 0.87)"><span style="font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif"><span style="background-color:#ffffff">提示:<a href="http://www.leftso.com/resource/1012.html" target="_blank" >项目源码下载</a></span></span></span></p> </blockquote>
  • Spring Boot Security 数据库方式入门案例

    spring boot 整合spring security采用mongodb数据库方式<p>案例中有使用mongodb数据库,具体的spring boot整合mongodb的案例参考地址<a href="http://www.leftso.com/blog/135.html" rel="nofollow" target="_blank">http://www.leftso.com/blog/135.html</a><br /> <br /> <a href="http://projects.spring.io/spring-security/" rel="nofollow" target="_blank">Spring Security</a>有一些使用复杂的意见。那当然,当你看的时候,它的范围很复杂,因为它的范围涵盖了大量的用例。事实上,真正的spring的精神,你不必一次使用你所拥有的用例的一切功能。事实上,当你开始使用<a href="http://projects.spring.io/spring-boot/" rel="nofollow" target="_blank">Spring Boot</a>进行樱桃挑选并将其恢复时,它似乎并不复杂。</p> <p>我们从使用情况开始,我在想一些比较常见的东西,几乎每个项目都出现一些基本的访问限制。所以,这样一个应用程序的要求可以是:</p> <ul> <li>该应用将有用户,每个用户角色为管理员或用户</li> <li>他们通过电子邮件和密码登录</li> <li>非管理员用户可以查看他们的信息,但不能窥视其他用户</li> <li>管理员用户可以列出并查看所有用户,并创建新的用户</li> <li>定制表单登录</li> <li>“记住我”验证懒惰</li> <li>注销的可能性</li> <li>主页将提供给所有人,不经过验证</li> </ul> <p>这样的<a href="https://github.com/bkielczewski/example-spring-boot-security" rel="nofollow" target="_blank">应用程序</a>的<a href="https://github.com/bkielczewski/example-spring-boot-security" rel="nofollow" target="_blank">源代码在GitHub上</a>,供您查看。建议您将源代码打开,以下将是某些关键点的评论。啊,和安全相关的东西接近尾声,所以只要知道基础知识就可以向下滚动。</p> <h4>依赖关系</h4> <p>此外,标准的Spring Boot依赖关系,最重要的依赖关系是Spring Security,Spring Data JPA的启动器模块,因为我们需要某处存储用户,而嵌入式内存中的HSQLDB作为存储引擎。</p> <pre> <code class="language-xml"><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> </dependency> </code></pre> <p>在现实生活中,您可能会更有兴趣连接到某种外部数据库引擎,例如<a href="http://kielczewski.eu/2014/05/database-connection-pooling-with-bonecp-in-spring-boot-application/" rel="nofollow" target="_blank">本文中关于使用BoneCP的数据库连接池的描述</a>。我也使用<a href="http://freemarker.org/" rel="nofollow" target="_blank">Freemarker</a>作为模板引擎,但是如果这不是你的事情,那么对于JSP来说,重写它也应该很简单,就像在<a href="http://kielczewski.eu/2014/04/spring-boot-mvc-application/" rel="nofollow" target="_blank">本文中关于Spring MVC应用程序一样</a>。</p> <h4>域模型</h4> <p>所以我们会有这样的<code>User</code>实体:</p> <pre> <code class="language-java">@Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false, updatable = false) private Long id; @Column(name = "email", nullable = false, unique = true) private String email; @Column(name = "password_hash", nullable = false) private String passwordHash; @Column(name = "role", nullable = false) @Enumerated(EnumType.STRING) private Role role; // getters, setters } </code></pre> <p>如您所见,只有密码的哈希将存储在数据库中,这通常是一个好主意。该<code>email</code>领域还有一个独特的约束,但它不是主要的关键。由于<code>id</code>某个原因,电子邮件地址是您不想在访问日志中显示的相当敏感的信息,因此用户被标识,所以我们将尽可能地使用id。</p> <p><code>Role</code> 是一个简单的枚举:</p> <pre> <code class="language-java">public enum Role { USER, ADMIN } </code></pre> <p>除此之外,创建新用户的表单将是很好的:</p> <pre> <code class="language-java">public class UserCreateForm { @NotEmpty private String email = ""; @NotEmpty private String password = ""; @NotEmpty private String passwordRepeated = ""; @NotNull private Role role = Role.USER; } </code></pre> <p>这将用作Web层和服务层之间的数据传输对象(DTO)。它由Hibernate Validator验证约束注释,并设置一些合理的默认值。请注意,它与<code>User</code>对象略有不同,因此我希望将<code>User</code>实体“泄漏” 到Web层中,我真的不能。</p> <p>这就是我们现在所需要的。</p> <h4>服务层</h4> <p>在服务层,业务逻辑应该是什么,我们需要一些东西来检索<code>User</code>他的id,电子邮件,列出所有的用户并创建一个新的用户。</p> <p>所以接口将是:</p> <pre> <code class="language-java">public interface UserService { Optional<User> getUserById(long id); Optional<User> getUserByEmail(String email); Collection<User> getAllUsers(); User create(UserCreateForm form); } </code></pre> <p>服务的实现:</p> <pre> <code class="language-java">@Service public class UserServiceImpl implements UserService { private final UserRepository userRepository; @Autowired public UserServiceImpl(UserRepository userRepository) { this.userRepository = userRepository; } @Override public Optional<User> getUserById(long id) { return Optional.ofNullable(userRepository.findOne(id)); } @Override public Optional<User> getUserByEmail(String email) { return userRepository.findOneByEmail(email); } @Override public Collection<User> getAllUsers() { return userRepository.findAll(new Sort("email")); } @Override public User create(UserCreateForm form) { User user = new User(); user.setEmail(form.getEmail()); user.setPasswordHash(new BCryptPasswordEncoder().encode(form.getPassword())); user.setRole(form.getRole()); return userRepository.save(user); } } </code></pre> <p>这里不值得一个评论 - 服务代理到<code>UserRepository</code>大部分时间。值得注意的是,在该<code>create()</code>方法中,该表单用于构建一个新<code>User</code>对象。哈希是从使用的密码<code>BCryptPasswordEncoder</code>生成的,这应该比臭名昭着的MD5产生更好的哈希。</p> <p>的<code>UserRepository</code>定义如下:</p> <pre> <code class="language-java">public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findOneByEmail(String email); } </code></pre> <p>这里只添加一个非默认方法<code>findOneByEmail</code>。请注意,我希望它返回<code>User</code>包装在JDK8中<code>Optional</code>,这是Spring的一个新功能,并且使处理<code>null</code>值更容易。</p> <h4>Web层</h4> <p>这是控制者及其观点。为了满足应用的要求,我们至少需要一对夫妇。</p> <h4>主页</h4> <p>我们将处理<code>/</code>网站的根<code>HomeController</code>,其中只返回一个<code>home</code>视图:</p> <pre> <code class="language-java">@Controller public class HomeController { @RequestMapping("/") public String getHomePage() { return "home"; } } </code></pre> <h4>用户列表</h4> <p>同样,用户的列表将被映射到<code>/users</code>并由其处理<code>UsersController</code>。它<code>UserService</code>注入,要求它返回<code>Collection</code>的<code>User</code>对象,将它们放入了<code>users</code>模型属性,然后调用<code>users</code>视图名称:</p> <pre> <code class="language-java">@Controller public class UsersController { private final UserService userService; @Autowired public UsersController(UserService userService) { this.userService = userService; } @RequestMapping("/users") public ModelAndView getUsersPage() { return new ModelAndView("users", "users", userService.getAllUsers()); } } </code></pre> <h4>查看和创建用户</h4> <p>接下来,我们需要一个控制器来处理查看和创建一个新的用户,我称之为它<code>UserController</code>,它更复杂:</p> <pre> <code class="language-java">@Controller public class UserController { private final UserService userService; private final UserCreateFormValidator userCreateFormValidator; @Autowired public UserController(UserService userService, UserCreateFormValidator userCreateFormValidator) { this.userService = userService; this.userCreateFormValidator = userCreateFormValidator; } @InitBinder("form") public void initBinder(WebDataBinder binder) { binder.addValidators(userCreateFormValidator); } @RequestMapping("/user/{id}") public ModelAndView getUserPage(@PathVariable Long id) { return new ModelAndView("user", "user", userService.getUserById(id) .orElseThrow(() -> new NoSuchElementException(String.format("User=%s not found", id)))); } @RequestMapping(value = "/user/create", method = RequestMethod.GET) public ModelAndView getUserCreatePage() { return new ModelAndView("user_create", "form", new UserCreateForm()); } @RequestMapping(value = "/user/create", method = RequestMethod.POST) public String handleUserCreateForm(@Valid @ModelAttribute("form") UserCreateForm form, BindingResult bindingResult) { if (bindingResult.hasErrors()) { return "user_create"; } try { userService.create(form); } catch (DataIntegrityViolationException e) { bindingResult.reject("email.exists", "Email already exists"); return "user_create"; } return "redirect:/users"; } } </code></pre> <p>视图被映射到<code>/user/{id}</code>URL,由<code>getUserPage()</code>方法处理。它要求<code>UserService</code>一个用户<code>id</code>,它是从URL中提取的,并作为参数传递给此方法。你记得,<code>UserService.getUserById()</code>返回一个<code>User</code>包装的实例<code>Optional</code>。因此,<code>.orElseThrow()</code>被要求<code>Optional</code>获得一个<code>User</code> 实例,或者在它的时候抛出异常<code>null</code>。</p> <p>创建一个新<code>User</code>的映射到<code>/user/create</code>并由两种方法处理:<code>getUserCreatePage()</code>和<code>handleUserCreateForm()</code>。第一个只返回一个<code>user_create</code>具有空格式的视图作为<code>form</code>模型的属性。另一个响应<code>POST</code>请求,并<code>UserCreateForm</code>作为参数进行验证。如果表单中有错误,则由<code>BindingResult</code>该视图返回。如果表单确定,则将其传递给<code>UserService.create()</code>方法。</p> <p>还有一个额外的检查<code>DataIntegrityViolationException</code>。如果发生这种情况,则认为是因为尝试<code>User</code>使用数据库中已经存在的电子邮件地址来创建,因此再次呈现该表单。</p> <p>在现实生活中,知道哪个约束被严重违反是非常困难的(或者与ORM无关),所以当做这些假设时,至少应该记录异常情况以便进一步检查。应该注意防止这种异常发生在第一位,如对于重复的电子邮件的形式的正确验证。</p> <p>否则,如果一切正常,则重定向到<code>/users</code>URL。</p> <h3>定制验证 <code>UserCreateForm</code></h3> <p>该<code>@InitBinder</code>在注解的方法<code>UserController</code>添加<code>UserCreateFormValidator</code>到<code>form</code>参数,告诉它应该由它来验证。这样做的原因在于,<code>UserCreateForm</code>需要对两种可能的情况进行整体验证:</p> <ul> <li>检查密码和重复密码是否匹配</li> <li>检查电子邮件是否存在于数据库中</li> </ul> <p>这样做,<code>UserCreateFormValidator</code>实现如下:</p> <pre> <code class="language-java">@Component public class UserCreateFormValidator implements Validator { private final UserService userService; @Autowired public UserCreateFormValidator(UserService userService) { this.userService = userService; } @Override public boolean supports(Class<?> clazz) { return clazz.equals(UserCreateForm.class); } @Override public void validate(Object target, Errors errors) { UserCreateForm form = (UserCreateForm) target; validatePasswords(errors, form); validateEmail(errors, form); } private void validatePasswords(Errors errors, UserCreateForm form) { if (!form.getPassword().equals(form.getPasswordRepeated())) { errors.reject("password.no_match", "Passwords do not match"); } } private void validateEmail(Errors errors, UserCreateForm form) { if (userService.getUserByEmail(form.getEmail()).isPresent()) { errors.reject("email.exists", "User with this email already exists"); } } } </code></pre> <h4>在登录</h4> <p>它将映射到<code>/login</code>URL并处理<code>LoginController</code>:</p> <pre> <code class="language-java">@Controller public class LoginController { @RequestMapping(value = "/login", method = RequestMethod.GET) public ModelAndView getLoginPage(@RequestParam Optional<String> error) { return new ModelAndView("login", "error", error); } } </code></pre> <p>请注意,它只处理<code>GET</code>请求方法,通过<code>error</code>在模型中返回具有可选参数的视图。<code>POST</code>表单的部分和实际处理将由Spring Security完成。</p> <p>表单的模板如下所示:</p> <pre> <code class="language-html"><form role="form" action="/login" method="post"> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> <div> <label for="email">Email address</label> <input type="email" name="email" id="email" required autofocus> </div> <div> <label for="password">Password</label> <input type="password" name="password" id="password" required> </div> <div> <label for="remember-me">Remember me</label> <input type="checkbox" name="remember-me" id="remember-me"> </div> <button type="submit">Sign in</button> </form> <#if error.isPresent()> <p>The email or password you have entered is invalid, try again.</p> </#if> </code></pre> <p>它具有普通<code>email</code>,<code>password</code>输入字段,一个<code>remember-me</code>复选框和一个提交按钮。如果出现错误,将显示说明认证失败的消息。</p> <p>这有效地包含了该应用程序功能所需的一切。剩下的是添加一些安全功能。</p> <h4>CSRF保护</h4> <p>关于<code>_csrf</code>上面窗体视图中出现的内容。它是由应用程序生成的用于验证请求的CSRF令牌。这是为了确保表单数据来自您的应用程序,而不是来自其他地方。这是Spring Security的一个功能,默认情况下由Spring Boot启动。</p> <p>对于JSP和Freemarker,<code>_csrf</code>变量只是暴露在视图中。它包含一个<code>CsrfToken</code>对象,该对象具有一个<code>getParameterName()</code>方法来获取一个CSRF参数名称(默认情况下是这个名称<code>_csrf</code>)和一个<code>getToken()</code>获取实际令牌的方法。然后,您可以将其放在一个隐藏的领域以及其余的表单中:</p> <pre> <code class="language-html"><input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> </code></pre> <h4>认证</h4> <p>现在我们有一个应用程序准备好了,是时候设置身份验证。当我们使用我们的登录表单识别那个人,作为现有用户,并且获得足够的信息以授权他们的进一步请求,认证意味着这一部分。</p> <h4>组态</h4> <p>需要添加Spring Security的此配置:</p> <pre> <code class="language-java">@Configuration @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .formLogin() .loginPage("/login") .failureUrl("/login?error") .usernameParameter("email") .permitAll() .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/") .permitAll(); } @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth .userDetailsService(userDetailsService) .passwordEncoder(new BCryptPasswordEncoder()); } } </code></pre> <p>这肯定需要一个解释。</p> <p>首先要提到的是<code>@Order</code>注释,它基本上保留了Spring Boot设置的所有默认值,只是在这个文件中覆盖它们。</p> <p>该<code>configure(HttpSecurity http)</code>方法是设置实际的基于URL的安全性。我们来看看它在这里做什么</p> <ul> <li>登录表格在下<code>/login</code>,允许所有。在登录失败时,<code>/login?error</code>会发生重定向。我们<code>LoginController</code>映射了这个URL。</li> <li>以登录形式保存用户名的参数称为“电子邮件”,因为这是我们用作用户名。</li> <li>注销URL是<code>/logout</code>允许的。之后,用户将被重定向到<code>/</code>。这里一个重要的意见是,如果CSRF保护开启,请求<code>/logout</code>应该是<code>POST</code>。</li> </ul> <p>该<code>configure(AuthenticationManagerBuilder auth)</code>方法是设置认证机制的地方。它的设置使得认证将被处理<code>UserDetailsService</code>,哪个实现被注入,并且密码预期被加密<code>BCryptPasswordEncoder</code>。</p> <p>值得一提的是还有很多其他的认证方法<code>UserDetailsService</code>。这只是一种使我们能够使用现有的服务层对象来实现的方法,因此它很适合这个应用。</p> <h3>UserDetailsS​​ervice</h3> <p>这<code>UserDetailsService</code>是Spring Security使用的接口,用于了解用户是否使用登录表单,他们的密码应该是什么,以及系统中有哪些权限。它有一个单一的方法:</p> <pre> <code class="language-java">public interface UserDetailsService { UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; } </code></pre> <p>如果用户名存在,则该方法<code>loadUserByUsername()</code>返回<code>UserDetails</code>实例,如果不存在则返回实例<code>UsernameNotFoundException</code>。</p> <p>我的实现,注入到同一个<code>SecurityConfig</code>如下:</p> <pre> <code class="language-java">@Service public class CurrentUserDetailsService implements UserDetailsService { private final UserService userService; @Autowired public CurrentUserDetailsService(UserService userService) { this.userService = userService; } @Override public CurrentUser loadUserByUsername(String email) throws UsernameNotFoundException { User user = userService.getUserByEmail(email) .orElseThrow(() -> new UsernameNotFoundException(String.format("User with email=%s was not found", email))); return new CurrentUser(user); } } </code></pre> <p>正如你所看到的,只是要求<code>UserService</code>有一个电子邮件的用户。如果不存在,抛出异常。如果是,<code>CurrentUser</code>则返回对象。</p> <p>但是呢<code>CurrentUser</code>?它应该是<code>UserDetails</code>。那么,首先,这<code>UserDetails</code>只是一个接口:</p> <pre> <code class="language-java">public interface UserDetails extends Serializable { Collection<? extends GrantedAuthority> getAuthorities(); String getPassword(); String getUsername(); boolean isAccountNonExpired(); boolean isAccountNonLocked(); boolean isCredentialsNonExpired(); boolean isEnabled(); } </code></pre> <p>它描述了具有用户名,密码,<code>GrantedAuthority</code>对象列表以及某些不明确标志的用户,这些标志由于各种帐户无效的原因而被描述。</p> <p>所以我们需要返回一个实现。至少有一个是Spring Security提供的<code>org.springframework.security.core.userdetails.User</code>。</p> <p>可以使用它,但棘手的部分是将我们的<code>User</code>域对象与<code>UserDetails</code>授权可能需要相关联。它可以通过多种方式完成:</p> <ul> <li>使<code>User</code>域对象<code>UserDetails</code>直接实现 - 它将允许返回<code>User</code>完全按照收到的方式<code>UserService</code>。缺点就是用与Spring Security相关的代码来“污染”域对象。</li> <li>使用提供的实现<code>org.springframework.security.core.userdetails.User</code>,只需将<code>User</code>实体映射到它。这很好,但是有一些关于用户可用的附加信息,如<code>id</code>直接访问<code>role</code>或其他任何东西是很好的。</li> <li>因此,第三个解决方案是扩展提供的实现,并添加可能需要的任何信息,或者只是一个完整的<code>User</code>对象。</li> </ul> <p>最后一个选择是我在这里使用的,所以<code>CurrentUser</code>:</p> <pre> <code class="language-java">public class CurrentUser extends org.springframework.security.core.userdetails.User { private User user; public CurrentUser(User user) { super(user.getEmail(), user.getPasswordHash(), AuthorityUtils.createAuthorityList(user.getRole().toString())); this.user = user; } public User getUser() { return user; } public Long getId() { return user.getId(); } public Role getRole() { return user.getRole(); } } </code></pre> <p>...扩展<code>org.springframework.security.core.userdetails.User</code>,实现<code>UserDetails</code>。此外,它只是包装我们的<code>User</code>域对象,加入(可选)方便的方法是代理给它(<code>getRole()</code>,<code>getId()</code>,等)。</p> <p>这个映射很简单,就是在构造函数中发生的:</p> <ul> <li>在<code>UserDetails.username</code>从填充<code>User.email</code></li> <li>在<code>UserDetails.password</code>从填充<code>User.passwordHash</code></li> <li>被<code>User.role</code>转换为<code>String</code>,由<code>AuthorityUtils</code>辅助类包装在GrantedAuthority对象中。它将作为列表的唯一元素<code>UserDetails.getAuthorities()</code>被调用时可用。</li> <li>我决定忘记这些标志,因为我没有使用它们,它们都是按照原样返回<code>true</code>的<code>org.springframework.security.core.userdetails.User</code></li> </ul> <p>话虽如此,我必须提到,当你传递这样的包裹实体时,要小心,或者直接实现它们<code>UserDetails</code>。像这样泄漏域对象并不是一件正确的事情。这也可能是有问题的,即如果实体有一些LAZY获取的关联,那么在尝试获取Hibernate会话之外时可能遇到问题。</p> <p>或者,只需从实体复制足够的信息<code>CurrentUser</code>。足够这里足以授权用户,而无需为<code>User</code>实体调用数据库,因为这将增加执行授权的成本。</p> <p>无论如何,这应该使我们的登录表单工作。总而言之,一步一步地发生的是:</p> <ul> <li>用户打开<code>/login</code>URL。</li> <li>的<code>LoginController</code>返回与登录形式的图。</li> <li>用户填写表单,提交。</li> <li>Spring Security调用<code>CurrentUserDetailsService.loadUserByUsername()</code>用户名(在这种情况下为电子邮件)刚刚输入到表单中。</li> <li><code>CurrentUserDetailsService</code>从中获取用户<code>UserDetailsService</code>并返回<code>CurrentUser</code>。</li> <li>Spring Security调用<code>CurrentUser.getPassword()</code>并将密码哈希与表单中提供的散列密码进行比较。</li> <li>如果没关系,用户被重定向到他来的地方<code>/login</code>,如果不是,重定向到<code>/login?error</code>,再次处理<code>LoginController</code>。</li> <li>Spring Security'保持' <code>CurrentUser</code>对象(包裹<code>Authentication</code>)用于授权检查,或者您应该需要它。</li> </ul> <h4>记住我的身份验证</h4> <p>有时候,对于那些不想输入登录表单的懒惰者,即使他们的会话过期,也可以“记住我”身份验证。这样会造成安全隐患,所以只要建议您使用它。</p> <p>它的工作原理如下:</p> <ul> <li>用户登录,表单发布一个<code>remember-me</code>参数(在此应用程序中有一个复选框)</li> <li>Spring Security生成一个令牌,保存它,并将其发送给一个名为cookie的用户<code>remember-me</code>。</li> <li>下一次访问应用程序时,Spring Security会查找该cookie,如果它保存有效和未过期的令牌,它将自动验证该用户。</li> <li>此外,您可以通过“记住我”来确定用户是否被认证。</li> </ul> <p>为了启用它,它只需要一些补充<code>SecurityConfig.configure(HttpSecurity http)</code>,所以它将看起来像这样:</p> <pre> <code class="language-java">@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .formLogin() .loginPage("/login") .failureUrl("/login?error") .usernameParameter("email") .permitAll() .and() .logout() .logoutUrl("/logout") .deleteCookies("remember-me") .logoutSuccessUrl("/") .permitAll() .and() .rememberMe(); } </code></pre> <p>注意<code>rememberMe()</code>到底。它使整个事情。值得注意的是,默认情况下,令牌存储在内存中。这意味着当应用程序重新启动时,令牌将丢失。你可以使它们持久化,即存储在数据库中,但对于这个应用程序来说,这是足够的。</p> <p>另一项新的事情是<code>deleteCookies()</code>对<code>logout()</code>。<code>remember-me</code>一旦用户从应用程序中注销,就会强制删除该cookie。</p> <h4>授权</h4> <p>授权是一个过程,找出那个已经被授权的人,我们知道他的一切,可以访问应用程序提供的指定资源。</p> <p>在这个应用程序中,我们将这些信息包含在一个<code>CurrentUser</code>对象中。从安全的角度来说,重要的是<code>GrantedAuthority</code>他所拥有的。你记得我们直接从<code>User.role</code>字段填充,所以他们将是“USER”或“ADMIN”。</p> <h4>基于URL的授权</h4> <p>现在,根据要求,我们希望所有人都可以访问某些网址,有些则由授权人员管理,还有一些由管理员访问。</p> <p>它需要一些补充<code>SecurityConfig</code>:</p> <pre> <code class="language-java">@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/", "/public/**").permitAll() .antMatchers("/users/**").hasAuthority("ADMIN") .anyRequest().fullyAuthenticated() .and() .formLogin() .loginPage("/login") .failureUrl("/login?error") .usernameParameter("email") .permitAll() .and() .logout() .logoutUrl("/logout") .deleteCookies("remember-me") .logoutSuccessUrl("/") .permitAll() .and() .rememberMe(); } </code></pre> <p>新的东西是电话<code>antMatchers()</code>。这强制执行:</p> <ul> <li>网址匹配<code>/</code>模式(此应用中的主页)和<code>/public/**</code>所有匹配的网址都将被允许。</li> <li>URL匹配<code>/users/**</code>模式(此应用程序中的列表视图)将仅允许具有“ADMIN”权限的用户。</li> <li>任何其他请求都需要经过身份验证的用户(“ADMIN”或“USER”)。</li> </ul> <h4>方法级授权</h4> <p>以上所有步骤都满足了大部分的要求,但是我们只能通过基于URL的授权无法解决。</p> <p>那是:</p> <ul> <li>管理员用户可以列出并查看所有用户,并创建新的用户</li> </ul> <p>这里的问题是,创建新用户的表单被映射到<code>/user/create</code>。我们可以添加这个URL <code>SecurityConfig</code>,但是如果我们做出一个习惯,我们最终会在配置文件中使用微型管理URL。我们也可以将其映射到<code>/users/create</code>这里,这可能在这里是有意义的,但是想到即将<code>/user/{id}/edit</code>来可能出现的那样。这是很好的离开它,因为它只是为了添加方法级别的授权给现有的方法<code>UserController</code>。</p> <p>要使方法级授权工作,<code>@EnableGlobalMethodSecurity(prePostEnabled = true)</code>需要将注释添加到<code>SecurityConfig</code>:</p> <pre> <code class="language-java">@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) class SecurityConfig extends WebSecurityConfigurerAdapter { // contents as before } </code></pre> <p>这使您可以在应用程序的任何层中对公共方法使用两个注释:</p> <ul> <li><code>@PreAuthorize("expression")</code>- 如果<code>expression</code>以<a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html" rel="nofollow" target="_blank">Spring表达式语言(Sprint)</a>编写的,它将评估为“true”,方法将被调用。</li> <li><code>@PostAuthorize("expression")</code> - 首先调用该方法,当检查失败时,403状态返回给用户。</li> </ul> <p>因此,为了解决第一个要求,处理用户创建的方法<code>UserController</code>需要注释<code>@PreAuthorize</code>:</p> <pre> <code class="language-java">@PreAuthorize("hasAuthority('ADMIN')") @RequestMapping(value = "/user/create", method = RequestMethod.GET) public ModelAndView getUserCreatePage() { // contents as before } @PreAuthorize("hasAuthority('ADMIN')") @RequestMapping(value = "/user/create", method = RequestMethod.POST) public String handleUserCreateForm(@Valid @ModelAttribute("form") UserCreateForm form, BindingResult bindingResult) { // contents as before } </code></pre> <p>该<code>hasAuthority()</code>规划环境地政司表达是由Spring Security的提供等等,即:</p> <ul> <li><code>hasAnyAuthority()</code>或者<code>hasAnyRole()</code>(“权限”和“角色”是Spring Security lingo中的同义词!) - 检查当前用户是否具有列表中的GrantedAuthority之一。</li> <li><code>hasAuthority()</code>或<code>hasRole()</code>- 如上所述,仅为一个。</li> <li><code>isAuthenticated()</code>或<code>isAnonymous()</code>- 当前用户是否被认证。</li> <li><code>isRememberMe()</code>或者<code>isFullyAuthenticated()</code>- 当前用户是否通过“记住我”令牌进行身份验证。</li> </ul> <h4>域对象安全</h4> <p>最后的要求是这样的:</p> <ul> <li>非管理员用户可以查看他们的信息,但不能窥视其他用户</li> </ul> <p>换句话说,我们需要一种方法来告诉用户什么时候可以请求<code>/user/{id}</code>。当用户是“ADMIN”(可以通过基于URL的身份验证来解决),而且当当前用户对自己发出请求时也是如此,这是不能解决的。</p> <p>这适用于以下方法<code>UserController</code>:</p> <pre> <code class="language-java"> @RequestMapping("/user/{id}") public ModelAndView getUserPage(@PathVariable Long id) { // contents as before } </code></pre> <p>我们需要检查当前用户是“管理” <strong>或</strong>在<code>id</code>传递给方法是一样的<code>id</code>从<code>User</code>与关联的域对象<code>CurrentUser</code>。由于<code>CurrentUser</code>有<code>User</code>实例包裹,我们有这方面的信息。所以我们可以用至少两种方法解决它:</p> <ul> <li>您可以使用Spel表达式来比较<code>id</code>传递给当前用户的方法<code>id</code>。</li> <li>您可以将此检查委托给服务 - 这是首选的,因为将来可能会改变条件,更好地在一个位置进行更改,而不是在使用注释的任何位置。</li> </ul> <p>要做到这一点,我<code>CurrentUserService</code>用这个界面创建了</p> <pre> <code class="language-java">public interface CurrentUserService { boolean canAccessUser(CurrentUser currentUser, Long userId); } </code></pre> <p>而这个实现:</p> <pre> <code class="language-java">@Service public class CurrentUserServiceImpl implements CurrentUserService { @Override public boolean canAccessUser(CurrentUser currentUser, Long userId) { return currentUser != null && (currentUser.getRole() == Role.ADMIN || currentUser.getId().equals(userId)); } } </code></pre> <p>现在在<code>@PreAuthorize</code>注释中使用它,只需放:</p> <pre> <code class="language-java">@PreAuthorize("@currentUserServiceImpl.canAccessUser(principal, #id)") @RequestMapping("/user/{id}") public ModelAndView getUserPage(@PathVariable Long id) { // contents as before } </code></pre> <p>哪个是用于调用具有principal(<code>CurrentUser</code>)实例的服务的SpEL表达式,并将<code>id</code>参数传递给方法。</p> <p>如果安全模型比较简单,这种方法可以正常工作。如果您发现自己写的东西类似于给予和检查多个访问权限,例如每个用户对多个域对象的查看/编辑/删除,那么最好是进入使用<a href="http://docs.spring.io/spring-security/site/docs/3.0.x/reference/domain-acls.html" rel="nofollow" target="_blank">Spring Security Domain对象ACL的方向</a>。</p> <p>这满足了所有的要求,此时应用程序得到了保障。</p> <h4>访问Spring Bean中的当前用户</h4> <p>无论何时需要从Controller或Service访问当前用户,都可以注入<code>Authentication</code>对象。可以通过调用获取当前的用户实例<code>Authentication.getPrincipal()</code>。</p> <p>这适用于构造函数或属性,如下所示:</p> <pre> <code class="language-java">@Autowired private Authentication authentication; void someMethod() { UserDetails currentUser = (UserDetails) authentication.getPrincipal(); } </code></pre> <p>此外,这适用于由<code>@RequestMapping</code>或者注释的控制器方法中的参数<code>@ModelAttribute</code>:</p> <pre> <code class="language-java">@RequestMapping("/") public String getMainPage(Authentication authentication) { UserDetails currentUser = (UserDetails) authentication.getPrincipal(); // something } </code></pre> <p>在这个应用程序中,可以直接转换<code>CurrentUser</code>,因为它<code>UserDetails</code>是正在使用的实际实现:</p> <pre> <code class="language-java">CurrentUser currentUser = (CurrentUser) authentication.getPrincipal(); </code></pre> <p>这样你也可以访问它所包围的域对象。</p> <h4>访问视图中的当前用户</h4> <p>访问当前身份验证的用户在视图中是有用的,即当为具有一定权限的用户呈现UI的某些元素时。</p> <p>在JSP中,可以使用安全标签库来完成,如下所示:</p> <pre> <code class="language-xml"><%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> <sec:authentication property="principal.username" /> </code></pre> <p>这应该打印当前用户的名字。对于Freemarker,也可以使用该taglib,尽管它需要更多的功能。</p> <p>您还可以拧紧taglib,并将<code>Authentication</code>对象作为视图的模型属性传递:</p> <pre> <code class="language-java">@RequestMapping("/") public String getMainPage(@ModelProperty("authentication") Authentication authentication) { return "some_view"; } </code></pre> <p>但是为什么不为所有的观点,使用<code>@ControllerAdvice</code>,只是<code>UserDetails</code>从<code>Authentication</code>:</p> <pre> <code class="language-java">@ControllerAdvice public class CurrentUserControllerAdvice { @ModelAttribute("currentUser") public UserDetails getCurrentUser(Authentication authentication) { return (authentication == null) ? null : (UserDetails) authentication.getPrincipal(); } } </code></pre> <p>之后,您可以通过<code>currentUser</code>所有视图中的属性访问它。</p>
  • spring boot 使用SLF4J Logging-Java编程

    Java编程之Spring Boot 使用SLF4J Logging,spring boot,SLF4J<h2>一、项目结构图</h2> <img alt="项目结构图" class="img-thumbnail" src="/resources/assist/images/blog/b33c0281356d4650ac605ee4715f5600.png" /><br /> 默认情况下,SLF4j日志记录包含在Spring boot包中。<br /> <strong>application.properties</strong> <pre> <code>spring-boot-web-project$ mvn dependency:tree +... +- org.springframework.boot:spring-boot-starter-logging:jar:1.4.2.RELEASE:compile [INFO] | | | +- ch.qos.logback:logback-classic:jar:1.1.7:compile [INFO] | | | | \- ch.qos.logback:logback-core:jar:1.1.7:compile [INFO] | | | +- org.slf4j:jcl-over-slf4j:jar:1.7.21:compile [INFO] | | | +- org.slf4j:jul-to-slf4j:jar:1.7.21:compile [INFO] | | | \- org.slf4j:log4j-over-slf4j:jar:1.7.21:compile +...</code></pre> <p><strong>请注意</strong><br /> <em>查看这个Spring Boot Logback XML模板,了解默认的日志记录模式和配置。</em></p> <h2>二、配置文件</h2> <h3>2.1application.properties<br /> 要启用日志记录,创建一个应用程序。在资源文件夹的根目录下的属性文件。<br /> 日志记录。级别-定义日志级别,日志记录将输出到控制台。<br /> <strong>application.properties</strong></h3> <pre> <code>logging.level.org.springframework.web=ERROR logging.level.com.mkyong=DEBUG</code></pre> logging.file -定义日志文件,日志将输出到一个文件和控制台。<br /> <strong>application.properties</strong> <pre> <code>logging.level.org.springframework.web=ERROR logging.level.com.mkyong=DEBUG #output to a temp_folder/file logging.file=${java.io.tmpdir}/application.log #output to a file #logging.file=/Users/mkyong/application.log</code></pre> <code>logging.pattern</code> -定义一个定制的日志记录模式。<br /> <strong>application.properties</strong> <pre> <code>logging.level.org.springframework.web=ERROR logging.level.com.mkyong=DEBUG # Logging pattern for the console logging.pattern.console= "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" # Logging pattern for file logging.pattern.file= "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" logging.file=/Users/mkyong/application.log</code></pre> <h2><strong>application.yml</strong></h2> 这在YAML格式中是一样的<br /> <strong>application.yml</strong> <pre> <code>logging: level: org.springframework.web: ERROR com.mkyong: DEBUG pattern: console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" file: /Users/mkyong/application.log</code></pre> <h2><strong>Classic Logback.xml</strong></h2> 如果您不喜欢Spring引导日志模板,只需创建一个标准的logback。xml在资源文件夹的根目录或类路径的根目录下。这将覆盖Spring引导日志模板。<br /> <strong>logback.xml</strong> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <configuration> <property name="DEV_HOME" value="c:/logs" /> <appender name="FILE-AUDIT" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${DEV_HOME}/debug.log</file> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <Pattern> %d{yyyy-MM-dd HH:mm:ss} - %msg%n </Pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily --> <fileNamePattern>${DEV_HOME}/archived/debug.%d{yyyy-MM-dd}.%i.log </fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <logger name="com.mkyong" level="debug" additivity="false"> <appender-ref ref="FILE-AUDIT" /> </logger> <root level="error"> <appender-ref ref="FILE-AUDIT" /> </root> </configuration></code></pre> <h2>Spring Boot logging by Profile</h2> <p>请注意<br /> 阅读本文-概要文件的配置<br />  </p> <p>创建一个logback-spring。在类路径的根目录中使用xml,以利用Spring引导提供的模板特性。</p> <p>在以下的例子:</p> <p>如果配置文件为dev,则将日志记录到控制台和一个滚动文件。</p> <p>如果概要文件被戳了,则只记录到一个滚动文件。<br /> <strong>logback-spring.xml</strong><br />  </p> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org/springframework/boot/logging/logback/defaults.xml"/> <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/> <springProfile name="dev"> <include resource="org/springframework/boot/logging/logback/console-appender.xml"/> <appender name="ROLLING-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> <file>${LOG_FILE}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.log</fileNamePattern> </rollingPolicy> </appender> <root level="ERROR"> <appender-ref ref="CONSOLE"/> <appender-ref ref="ROLLING-FILE"/> </root> </springProfile> <springProfile name="prod"> <appender name="ROLLING-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> <file>${LOG_FILE}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <root level="ERROR"> <appender-ref ref="ROLLING-FILE"/> </root> </springProfile> </configuration></code></pre> <br /> <strong>application.yml</strong> <pre> <code>spring: profiles: active: prod logging: level: ROOT: ERROR org.springframework: ERROR org.springframework.data: ERROR com.mkyong: INFO org.mongodb: ERROR file: /Users/mkyong/application.log</code></pre> 对于非web启动应用程序,您可以像这样覆盖日志文件输出: <pre> <code>$ java -Dlogging.file=/home/mkyong/app/logs/app.log -jar boot-app.jar</code></pre> <h2>Set Root Level</h2> <strong>application.properties</strong> <pre> <code># root logging level, warning : too much output logging.level.=DEBUG</code></pre> <strong>application.yml</strong> <pre> <code>logging: level: ROOT: DEBUG</code></pre> <br /> <a href="http://www.mkyong.com/wp-content/uploads/2017/01/spring-boot-web-slf4j-logging.zip" rel="external nofollow" target="_blank">下载演示demo</a>