读书笔记-深入浅出spirngboot2

第一章

  • springboot的依赖和自动配置
spring-boot-starter-web引入了下面的包
 <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.0.0.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-json</artifactId>
      <version>2.0.0.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.0.0.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.hibernate.validator</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.0.7.Final</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.0.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>https://i.cnblogs.com/EditPosts.aspx?opt=1
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.0.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

第二章 自定义配置

  • 在运行前还需要做一些配置
    autoconfig中的配置类:
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
//配置文件
@Configuration
//配置需要满足类型是Servlet
@ConditionalOnWebApplication(type = Type.SERVLET)
//需要是DispatcherServlet类
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
//自动配置servlet相关的属性,这样就能做到自动配置
@EnableConfigurationProperties(ServerProperties.class)
public class DispatcherServletAutoConfiguration {

  • 配置文件加载优先级:

bootstrap.properties优先于application.prperties
properties优先于yml
resources/config优先于resources/

第三章 全注解下的Spring IOC

  • 所有IOC容器都要实现接口BeanFactory,他是一个顶级接口
//isSingleton判断是否单例,默认情况下bean都是单例(isSingleton返回true),如果是isPrototype返回true,则是多例模式,每次调用getBean会返回一个新的bean
public interface BeanFactory {

	String FACTORY_BEAN_PREFIX = "&";

	Object getBean(String name) throws BeansException;
	
	<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;

	Object getBean(String name, Object... args) throws BeansException;

	<T> T getBean(Class<T> requiredType) throws BeansException;

	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	boolean containsBean(String name);
	
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	String[] getAliases(String name);
}

  • Spring在BeanFactory的基础上,设置了一个更高级的接口ApplicationContext,他是BeanFactory的子接口之一,实际上使用的都是ApplicationContext的实现类


  • 简单注入bean的方法
1.声明实体类
public class User {
	private Long id;
	private String userName;
	private String note;
}
2.增加配置类
@Configuration
public class AppConfig {
	
	@Bean(name="user")
	public User init(){
		User user  = new User();
		user.setId(1L);
		user.setUserName("aaa");
		user.setNote("note_1");
		return user;


	}
}
3.使用
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
		User u = (User) ctx.getBean("user");
		System.out.println(u.getId());

	}
  • 通过扫描注入bean
    @ComponentScan会扫描当前包和子包
@Component("user")
public class User {
	private Long id;
	private String userName;
	private String note;
}

@Configuration
@ComponentScan
public class AppConfig {
	@Bean(name="user")
	public User init(){
		User user  = new User();
		user.setId(1L);
		user.setUserName("aaa");
		user.setNote("note_1");
		return user;
	}
}

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
		User u = (User) ctx.getBean(User.class);
		System.out.println(u.getId());
	}
  • ComponentScan源码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//在一个类中可以重复定义
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
	//定义扫描的包
	@AliasFor("basePackages")
	String[] value() default {};
	//定义扫描的包
	@AliasFor("value")
	String[] basePackages() default {};
	//定义扫描的类
	Class<?>[] basePackageClasses() default {};
	//Bean name 生成器
	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
	//作用域解析器
	Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
	//作用域代理模式
	ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
	//资源匹配模式
	String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
	//启用默认过滤器
	boolean useDefaultFilters() default true;
	//当满足过滤器的条件时扫描
	Filter[] includeFilters() default {};
	//当不满足过滤器条件时扫描
	Filter[] excludeFilters() default {};
	//是否延迟初始化
	boolean lazyInit() default false;
	//定义过滤器
	@Retention(RetentionPolicy.RUNTIME)
	@Target({})
	@interface Filter {
		//过滤器类型
		FilterType type() default FilterType.ANNOTATION;
		//定义过滤的类
		@AliasFor("classes")
		Class<?>[] value() default {};
		//定义过滤的类
		@AliasFor("value")
		Class<?>[] classes() default {};
		//匹配方式
		String[] pattern() default {};
	}
}
  • SpringBootApplication源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
//自定义排除的扫描类
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

	//通过类型排除自动配置类
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

	//通过名称排除自动配置类
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};

	//定义扫描包
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

	//定义被扫描的类
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};
}

  • 自定义第三方bean
Configuration
@ComponentScan(basePackages = "com.springboot.chapter3.*", 
excludeFilters = {@Filter(classes = {})})
public class AppConfig {
	
	@Bean(name = "dataSource")
	public DataSource getDataSource() {
	    Properties props = new Properties();
	    props.setProperty("driver", "com.mysql.jdbc.Driver");
	    props.setProperty("url", "jdbc:mysql://localhost:3306/chapter3");
	    props.setProperty("username", "root");
	    props.setProperty("password", "123456");
	    DataSource dataSource = null;
	    try {
	        dataSource = BasicDataSourceFactory.createDataSource(props);
	    } catch (Exception e) {
	        e.printStackTrace();
	    }
	    return dataSource;
	}
}

  • @AutoWired
    默认是by type注入
    如果一个接口有多个实现类,在注入时会有歧义,利用@Primary和@Quelifier可以消除歧义
    例如:


    @Primary: 当发现多个同样类型的bean时,可以优先注入
    @Quelifier: 和@AutoWired一起使用时,可以通过类型和Quelifier定义的名称一起找到bean
  • bean生命周期

    ComponentScan还有一个配置项lazyInit,只可以配置boolean值,默认是false,也就是默认不进行延迟初始化
    配置为true的话就是等到使用的时候才进行注入

bean生命周期

  • 前和后预初始化方法(针对所有的bean都生效)
@Component
public class BeanPostProcessorExample implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("BeanPostProcessor调用postProcessBeforeInitialization方法,参数【" 
		        + bean.getClass().getSimpleName()+ "】【" +beanName+"】 ");
		return bean;
	}
	
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("BeanPostProcessor调用postProcessAfterInitialization方法,参数【" 
	        + bean.getClass().getSimpleName()+ "】【" +beanName+"】 ");
		return bean;
	}

	

}
  • 使用属性文件
属性文件依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

有了依赖,可以直接使用application.properties
如果配置文件中是database.driverName=**这种,可以直接在配置类中使用@ConfigurationProperties( "database"),否则可以使用@Value单个属性配置
如果不是application.properties可以使用自定义加载 @PropertySource(value={"classpath:jdbc.properties"}, ignoreResourceNotFound=true)

  • 条件装配Bean
    有时候有一些客观原因使bean无法初始化,如:在数据库连接池中漏掉一些配置使数据库连接不上,这个时候可以使用@Condition,当条件不满足的时候不加载
加上@Conditional(DatabaseConditional.class)后,需要增加实现类,在实现类中添加过滤的规则,如果过滤的规则如果不符合则不装配这个bean
@Bean(name = "dataSource", destroyMethod = "close")
	@Conditional(DatabaseConditional.class)
	public DataSource getDataSource(
			@Value("${database.driverName}") String driver,
			@Value("${database.url}") String url,
			@Value("${database.username}") String username,
			@Value("${database.password}") String password
			) {
		Properties props = new Properties();
		props.setProperty("driver", driver);
		props.setProperty("url", url);
		props.setProperty("username", username);
		props.setProperty("password", password);
		DataSource dataSource = null;
		try {
			dataSource = BasicDataSourceFactory.createDataSource(props);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return dataSource;
	}

public class DatabaseConditional implements Condition {

	@Override
	/*
	 * 
	 * @param context 条件上下文
	 * @param 
	 */
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		Environment env = context.getEnvironment();
		return env.containsProperty("database.driverName") && env.containsProperty("database.url") 
				&& env.containsProperty("database.username") && env.containsProperty("database.password");
	}

}

Bean作用域

  • 常用bean作用域有两种: 单例和原型
  • @Profile 区分不同的环境
@Bean(name = "dataSource", destroyMethod = "close")
	@Profile("dev")
	public DataSource getDevDataSource() {
		Properties props = new Properties();
		props.setProperty("driver", "com.mysql.jdbc.Driver");
		props.setProperty("url", "jdbc:mysql://localhost:3306/dev_spring_boot");
		props.setProperty("username", "root");
		props.setProperty("password", "123456");
		DataSource dataSource = null;
		try {
			dataSource = BasicDataSourceFactory.createDataSource(props);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return dataSource;
	}


	@Bean(name = "dataSource", destroyMethod = "close")
	@Profile("test")
	public DataSource getTestDataSource() {
		Properties props = new Properties();
		props.setProperty("driver", "com.mysql.jdbc.Driver");
		props.setProperty("url", "jdbc:mysql://localhost:3306/test_spring_boot");
		props.setProperty("username", "root");
		props.setProperty("password", "123456");
		DataSource dataSource = null;
		try {
			dataSource = BasicDataSourceFactory.createDataSource(props);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return dataSource;
	}

spring启动时先判断有没有spring.profiles.active,然后判断spring.profiles.default,如果这两个参数都没有配置,spring就不会启动Profile机制,被@Profile标志的bean都不会被加载

  • ImportResource 引入对应的XML文件:在配置类加上@ImportResource(value = {"classpath:spring-other.xml"})

第五章 访问数据库

  • mybatis配置结构图

第六章 事务处理

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
	//通过bean name指定事务管理器
	@AliasFor("transactionManager")
	String value() default "";
	
	@AliasFor("value")
	String transactionManager() default "";
	//指定传播行为
	Propagation propagation() default Propagation.REQUIRED;
	//指定隔离级别
	Isolation isolation() default Isolation.DEFAULT;
	//指定超时时间
	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
	//只读事物
	boolean readOnly() default false;
	//方法发生指定异常时回滚,默认是所有都回滚
	Class<? extends Throwable>[] rollbackFor() default {};
	//方法发生指定异常名称时回滚,默认所有异常回滚
	String[] rollbackForClassName() default {};
	//方法指定异常不回滚
	Class<? extends Throwable>[] noRollbackFor() default {};
	//方法指定异常名称不回滚
	String[] noRollbackForClassName() default {};
}

@Transactional 可以放在接口也可以放在实现类上,推荐放在实现类上,使用接口的话只能用jdk动态代理,不能使用CGLIB动态代理

  • 事务管理器
  • 事务隔离级别
    1.未提交读: 允许一个事务读取另外一个事务没有提交的数据(比较危险,实际很少使用,但是并发能力高),会出现脏读

2.读写提交: 一个事务只能读取另外一个事务已经提交的数据,不能读取未提交的数据

会出现不可重复读:

3.可重复读:

会出现幻读



4.串行化:sql完全串行执行


  • 传播行为

在spring中,当一个方法调用另外一个方法时,可以让事务采取不同的策略工作

public enum Propagation {
	//如果当前存在事务则沿用当前事务,否则新建一个事务运行字方法
	REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
	//如果当前存在事务则沿用当前事务,否则以无事务方式运行
	SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
	//必须使用事务,如果当前没有事务则抛异常,如果当前存在事务则沿用当前事务
	MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
	//无论当前事务是否存在,都新建运行事务的方法,与当前事务独立
	REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
	//不支持事务,如果当前有事务,则挂起事务运行方法
	NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
	//不支持事务,如果当前有事务则抛异常,如果没有则继续执行
	NEVER(TransactionDefinition.PROPAGATION_NEVER),
	//在当前方法调用字方法时,如果子方法发生异常,只回滚子方法的sql,不回滚当前事务
	NESTED(TransactionDefinition.PROPAGATION_NESTED);
	private final int value;
	Propagation(int value) { this.value = value; }
	public int value() { return this.value; }
}

  • @Transactional自调用失效
    spring事务的实现方式是AOP,AOP原理是动态代理,在自调用的过程中,是类自身的调用,而不是代理对象去调用,就不会产生AOP,
    这样Spring就不能把你的代码织入约定的流程中,为了使事务有效,要改成用一个service去调用另外一个service,这样才会触发AOP
  • 事务不生效原因汇总:
    1.没有被spring管理
    2.方法不是public,只有public的方法才会被代理
    3.自调用
    4.数据源没有配置事务管理器
    5.数据库引擎不支持事务
    6.异常被吃了,没有抛出来
    7.异常配型配置错误,默认的是RuntimeException如果想抛其他类型,加上@Transactional(rollbackFor = Exception.class)

第七章 使用redis

  • Spring通过RedisConnection操作redis,RedisConnection是对原生的redis进行封装,要获取RedisConnection对象,需要通过RedisConnectionFactory生成
    所有使用redis的第一步是配置这个工厂,主要是配置Redis连接池
redis依赖
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
	<exclusions>
		<!--不依赖Redis的异步客户端lettuce -->
		<exclusion>
			<groupId>io.lettuce</groupId>
			<artifactId>lettuce-core</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<!--引入Redis的客户端驱动jedis -->
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
</dependency>
配置Redis连接池和配置RedisTemplate
public class RedisConfig {

	private RedisConnectionFactory connectionFactory = null;

	@Bean(name = "redisConnectionFactory")
	public RedisConnectionFactory initConnectionFactory() {
		if (this.connectionFactory != null) {
			return this.connectionFactory;
		}
		JedisPoolConfig poolConfig = new JedisPoolConfig();
		// 最大空闲数
		poolConfig.setMaxIdle(50);
		// 最大连接数
		poolConfig.setMaxTotal(100);
		// 最大等待毫秒数
		poolConfig.setMaxWaitMillis(2000);
		// 创建Jedis连接工厂
		JedisConnectionFactory connectionFactory = new JedisConnectionFactory(poolConfig);
		// 配置Redis连接服务器
		RedisStandaloneConfiguration rsc = connectionFactory.getStandaloneConfiguration();
		rsc.setHostName("192.168.20.4");
		rsc.setPort(6379);
		//rsc.setPassword(RedisPassword.of("123456"));
		this.connectionFactory = connectionFactory;
		return connectionFactory;
	}
	
	@Bean(name="redisTemplate")
	public RedisTemplate<Object, Object> initRedisTemplate() {
	    RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
	    redisTemplate.setConnectionFactory(initConnectionFactory());
	    RedisSerializer<String> stringRedisSerializer = redisTemplate.getStringSerializer();
	    redisTemplate.setKeySerializer(stringRedisSerializer);
	    redisTemplate.setHashKeySerializer(stringRedisSerializer);
	    redisTemplate.setHashValueSerializer(stringRedisSerializer);
	  return redisTemplate;
	}
}

测试RedisTemplate
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(RedisConfig.class);
		RedisTemplate redisTemplate = ctx.getBean(RedisTemplate.class);
		redisTemplate.opsForValue().set("key1", "value1");
		redisTemplate.opsForHash().put("hash", "field", "hvalue");
		ctx.close();
	}


  • 如果没有配置序列化器,则默认使用JdkSerializationRedisSerializer序列化器

  • 使用字符串序列化器

  • StringRedisTemplate,继承RedisTemplate,只是提供了字符串的操作

  • Redis能支持7中数据类型
    字符串,散列,列表,集合,有序集合,基数和地理位置

  • 如果需要连续操作多个命令,则可以使用以下接口

  • springboot中使用redis
    1.配置属性

    2.修改RedisTemplate序列化器,不然就会使用默认的JdkSerializationRedisSerializer序列化器

    3.使用RedisTemplate操作数据

  • Redis事务

  • 流水线执行模式提高速度

public Map<String, Object> testPipeline() {
		Long start = System.currentTimeMillis();
		List list = (List) redisTemplate.executePipelined((RedisOperations operations) -> {
			for (int i = 1; i <= 100000; i++) {
				operations.opsForValue().set("pipeline_" + i, "value_" + i);
				String value = (String) operations.opsForValue().get("pipeline_" + i);
				if (i == 100000) {
					System.out.println("命令只是进入队列,所以值为空【" + value + "】");
				}
			}
			return null;
		});
		Long end = System.currentTimeMillis();
		System.out.println("耗时:" + (end - start) + "毫秒。");
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("success", true);
		return map;
	}
  • Redis发布订阅
消息监听器
@Component
public class RedisMessageListener implements MessageListener {
    @Override
    public void onMessage(Message message, byte[] pattern) {
        // 消息体
        String body = new String(message.getBody());
        // 渠道名称
        String topic = new String(pattern); 
        System.out.println(body);
        System.out.println(topic);
    }
}
	// 设置RedisTemplate的序列化器
	private void initRedisTemplate() {
		RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
		redisTemplate.setKeySerializer(stringSerializer);
		redisTemplate.setHashKeySerializer(stringSerializer);
	}

	// RedisTemplate
	@Autowired
	private RedisTemplate redisTemplate = null;
	
	// Redis连接工厂
	@Autowired
	private RedisConnectionFactory connectionFactory = null;

	// Redis消息监听器
	@Autowired
	private MessageListener redisMsgListener = null;

	// 任务池
	private ThreadPoolTaskScheduler taskScheduler = null;

	/**
	 * 创建任务池,运行线程等待处理Redis的消息
	 *
	 * @return
	 */
	@Bean
	public ThreadPoolTaskScheduler initTaskScheduler() {
		if (taskScheduler != null) {
			return taskScheduler;
		}
		taskScheduler = new ThreadPoolTaskScheduler();
		taskScheduler.setPoolSize(20);
		return taskScheduler;
	}

	/**
	 * 定义Redis的监听容器
	 *
	 * @return 监听容器
	 */
	@Bean
	public RedisMessageListenerContainer initRedisContainer() {
		RedisMessageListenerContainer container = new RedisMessageListenerContainer();
		// Redis连接工厂
		container.setConnectionFactory(connectionFactory);
		// 设置运行任务池
		container.setTaskExecutor(initTaskScheduler());
		// 定义监听渠道,名称为topic1
		Topic topic = new ChannelTopic("topic1");
		// 使用监听器监听Redis的消息
		container.addMessageListener(redisMsgListener, topic);
		return container;
	}

	public static void main(String[] args) {
		SpringApplication.run(Chapter7Application.class, args);
	}

当在redis执行publish topic1 msg时会收到信息

  • 使用lua脚本

	public Map<String, Object> testLua2(String key1, String key2, String value1, String value2) {
		// 定义Lua脚本
		String lua = " redis.call('set', KEYS[1], ARGV[1]) \n" 
		        + " redis.call('set', KEYS[2], ARGV[2]) \n"
				+ " local str1 = redis.call('get', KEYS[1]) \n" 
		        + " local str2 = redis.call('get', KEYS[2]) \n"
				+ " if str1 == str2 then  \n" + "return 1 \n" 
		        + " end \n" 
				+ " return 0 \n";
		System.out.println(lua);
		// 结果返回为Long
		DefaultRedisScript<Long> rs = new DefaultRedisScript<Long>();
		rs.setScriptText(lua);
		rs.setResultType(Long.class);
		// 采用字符串序列化器
		RedisSerializer<String> stringSerializer = redisTemplate.getStringSerializer();
		// 定义key参数
		List<String> keyList = new ArrayList<>();
		keyList.add(key1);
		keyList.add(key2);
		// 传递两个参数值,其中第一个序列化器是key的序列化器,第二个序列化器是参数的序列化器
		Long result = (Long) redisTemplate.execute(rs, stringSerializer, stringSerializer, keyList, value1, value2);
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("result", result);
		return map;
	}

第八章 使用MongoDb

  • 实体类加上@Document 标识为MongoDB文档
  • @Field("user_name") MongoDB一般用下划线表示字段,所以要加别名
操作MongoDB的方法
@Service
public class UserServiceImpl implements UserService {

	// 注入MongoTemplate对象
	@Autowired
	private MongoTemplate mongoTmpl = null;

	@Override
	public User getUser(Long id) {
		return mongoTmpl.findById(id, User.class);
		// 如果只需要获取第一个也可以采用如下查询方法
		// Criteria criteriaId = Criteria.where("id").is(id);
		// Query queryId = Query.query(criteriaId);
		// return mongoTmpl.findOne(queryId, User.class);
	}

	@Override
	public List<User> findUser(String userName, String note, int skip, int limit) {
		// 将用户名称和备注设置为模糊查询准则
		Criteria criteria = Criteria.where("user_name").regex(userName).and("note").regex(note);
		// 构建查询条件,并设置分页跳过前skip个,至多返回limit个
		Query query = Query.query(criteria).limit(limit).skip(skip);
		// 执行
		List<User> userList = mongoTmpl.find(query, User.class);
		return userList;
	}

	@Override
	public void saveUser(User user) {
		// 使用名称为user文档保存用户信息
		mongoTmpl.save(user, "user");
		// 如果文档采用类名首字符小写,则可以这样保存
		// mongoTmpl.save(user);
	}

	@Override
	public DeleteResult deleteUser(Long id) {
		// 构建id相等的条件
		Criteria criteriaId = Criteria.where("id").is(id);
		// 查询对象
		Query queryId = Query.query(criteriaId);
		// 删除用户
		DeleteResult result = mongoTmpl.remove(queryId, User.class);
		return result;
	}

	@Override
	public UpdateResult updateUser(Long id, String userName, String note) {
		// 确定要更新的对象
		Criteria criteriaId = Criteria.where("id").is(id);
		Query query = Query.query(criteriaId);
		// 定义更新对象,后续可变化的字符串代表排除在外的属性
		Update update = Update.update("user_name", userName);
		update.set("note", note);
		// 更新单个对象
		UpdateResult result = mongoTmpl.updateFirst(query, update, User.class);
		// 更新多个对象
		// UpdateResult result2 = mongoTmpl.updateMulti(query, update, User.class);
		return result;
	}

}

posted @ 2020-12-07 08:11  余***龙  阅读(145)  评论(0编辑  收藏  举报