1、项目创建,工程主界面如下:
2、编写HelloController.java :
@RestController
public class HelloController {
@GetMapping("/hello")
public String sayHello() {
return "hello spring Boot!";
}
}
3、启动SpringbootDemoApplication类main方法:
4、访问http://localhost:8080/hello
添加devtools依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
开启热部署
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!--在原来spring-boot-maven-plugin 追加以下语句:开启热部署-->
<configuration>
<fork>true</fork>
</configuration>
</plugin>
使用示例:
新建pojo:Goods.java
package com.offcn.demo.bean;
import java.util.Date;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
public class Goods{
private int id;
private String name;
private float price;
//格式化输出,格式化日期时间类型
//GMT 是世界标准时间。中国所在时区就是gmt+8 。
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd hh:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")
private Date createDate;
//忽略字段,不转换为json
@JsonIgnore
private String memo;
//当属性值为空时候,不转换为json
@JsonInclude(JsonInclude.Include.NON_NULL)
private String isnull;
private String email;
//Set、get方法略
}
创建controller:GoodsController.java
@RestController
public class GoodsController {
@RequestMapping("/getGoods1")
public Goods getGoods() {
Goods goods = new Goods();
goods.setId(1);
goods.setName("测试");
goods.setPrice(100000.99F);
goods.setCreateDate(new Date());
goods.setMemo("描述");
goods.setIsnull("不为空显示");
return goods;
}
@InitBinder
private void initBinder(WebDataBinder webDataBinder){
webDataBinder.addCustomFormatter(new DateFormatter("yyyy-MM-dd HH:mm:ss"));
}
}
启动访问
@RequestMapping("/getGoods2/{name}")
public Goods getGoodsById(@RequestParam(name="id") Integer id,
@PathVariable(name="name") String name) {
Goods goods = new Goods();
goods.setId(id);
goods.setName(name);
goods.setPrice(100000.99F);
goods.setCreateDate(new Date());
goods.setMemo("描述");
goods.setIsnull("不为空显示");
return goods;
}
@RequestMapping("/getGoods3")
public Goods getGoodsById(@RequestBody Goods goods) {
return goods;
}
{"id":999,"name":"兰博基尼","price":9999.98,"createDate":"2018-12-15 9:18:28","memo":"描述","isnull":"不为空"}
普通的表单提交方式。
@RequestMapping("/getGoods4")
public Goods getGoodsById(Goods goods) {
return goods;
}
@InitBinder
private void initBinder(WebDataBinder webDataBinder){
webDataBinder.addCustomFormatter(new DateFormatter("yyyy-MM-dd HH:mm:ss"));
}
//[a-zA-Z0-9_]+ 表达式指定了 group 必须是以大小写字母、数字或下划线组成的字符串。
@GetMapping("/user/{id:[a-zA-Z0-9_]+}")
public String getUserById(@PathVariable String id){
return "根据id查询用户:"+id;
}
尝试访问地址:http://localhost:8080/user/a8799
http://localhost:8080/user/a87-99
@RestController
@Validated //开启数据有效性校验,添加在类上即为验证方法,/// 添加在方法参数中即为验证参数对象。
public class UserController {
@GetMapping("/demo123")
public String user(@NotBlank(message = "id不能为空!") @RequestParam("userid") String id,
@NotBlank(message = "name不能为空!") @RequestParam("username") String name,
@Email(message = "email格式不正确!") String email){
return id+"==》"+name;
}
}
测试:http://localhost:8080/valid2?group=&email=11
这里的异常名称叫ConstraintViolationException(违反约束异常)
附带异常的处理:
编写统一异常处理类
处理单个异常:
@ControllerAdvice //增强的 Controller 可以用来 全局异常处理 全局数据绑定和预处理 本示例处理异常
public class GlobalExceptionHandler {
//@ExceptionHandler 是 Controller层面上异常处理注解
@ExceptionHandler(ConstraintViolationException.class)//参数校验异常
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST) //400 : 参数报错
public String handleValidationException(ConstraintViolationException e){
String msg = "请求参数不合法, ";
for(ConstraintViolation<?> s:e.getConstraintViolations()){
msg += s.getInvalidValue()+": "+s.getMessage() + ";";
}
return msg;
}
}
处理多个异常:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class) //Exception
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String handleValidationException(Exception e){
if(e instanceof ConstraintViolationException ){
ConstraintViolationException exception = (ConstraintViolationException)e;
for(ConstraintViolation<?> s:exception.getConstraintViolations()){
return s.getInvalidValue()+": "+s.getMessage();
}
}else if(e instanceof MethodArgumentNotValidException){
return ((MethodArgumentNotValidException) e).getBindingResult().getFieldError().getDefaultMessage();
}
return "请求参数不合法";
}
}
注解 | 作用 |
---|---|
@Validated (重要) | 开启数据有效性校验,添加在类上即为验证方法,添加在方法参数中即为验证参数对象。 |
@NotNull | 限制字段必须不为null value != null ? true : false |
@NotEmpty | 验证注解的元素值不为 null 且不为空,可用在字符串或集合。(字符串长度不为0、集合大小不为0) |
@NotBlank | 验证注解的元素值不为空(不为null、去除首位空格后长度为0),@NotBlank只应用于字符串且在比较时会去除字符串的空格 value.trim() > 0 ? true : false |
@Pattern(value) | 限制必须符合指定的正则表达式 |
@Size(max,min) | 限制字符长度必须在 min 到 max 之间(也可以用在集合上) |
验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式 | |
@Max(value) | 限制必须为一个不大于指定值的数字 对应的数据库表字段也会添加一个check的约束条件 |
@Min(value) | 限制必须为一个不小于指定值的数字 同上 |
@DecimalMax(value) | 限制必须为一个不大于指定值的数字 没有上述作用 |
@DecimalMin(value) | 限制必须为一个不小于指定值的数字 |
@Null | 限制只能为null(很少用) |
@AssertFalse | 限制必须为false (很少用) |
@AssertTrue | 限制必须为true (很少用) |
@Past | 限制必须是一个过去的日期 |
@Future | 限制必须是一个将来的日期 |
@Digits(integer,fraction) | 限制必须为一个小数,且整数部分的位数不能超过 integer,小数部分的位数不能超过 fraction (很少用) |
@Length | 被注释的字符串的大小必须在指定的范围内 |
示例:
1、修改Goods增加对参数的校验规则
public class Goods {
@Max(value=100,message="id不能大于100")
private int id;
@NotBlank(message="用户名不能为空")
@Length(min = 2, max = 10, message = "用户名 长度必须在 {min} - {max} 之间")
private String name;
@DecimalMin(value="1.0",message="价格最低1元")
@DecimalMax(value="10.0",message="价格最高10元")
private float price;
//格式化日期时间类型
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd hh:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")
private Date createDate;
//忽略字段,不转换为json
@JsonIgnore
private String memo;
//复杂校验
//当属性值为空时候,不转换为json
@JsonInclude
@NotNull(message="属性字段不能为空")
@NotBlank(message="属性字段不能为空白")
private String isnull;
@NotBlank(message="手机号不能为空")
@Pattern(regexp = "^((17[0-9])|(14[0-9])|(13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$",
message = "手机号格式不合法")
private String telephone;
//验证邮箱格式
@Pattern(regexp = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$",
message = "邮箱格式不合法")
private String email;
//Set get方法略
}
2、创建Controller
@RestController
public class GoodsValidation {
@RequestMapping("/getGoodsvalidation1")
public Goods getGoodsvalidation1(@RequestBody @Validated Goods goods) {
return goods;
}
}
3、
{"id":999,"name":"你好","price":8.98,"createDate":"2018-12-15 9:18:28","memo":"描述","isnull":"不为空"}
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 将所有D:\\springboot\\pic\\ 访问都 映射到 /myPic/** 路径下
registry.addResourceHandler("/myPic/**").addResourceLocations("file:D:\\springboot\\pic\\");
}
}
web.upload-path=D:/springboot/pic/
spring.mvc.static-path-pattern=/**
spring.resources.static-locations=classpath:/a/b/,classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${web.upload-path}
# 注意:
# web.upload-path:这个属于自定义的属性,指定了一个路径,注意要以/结尾;
# spring.mvc.static-path-pattern=/**:表示所有的访问都经过静态资源路径;
# spring.resources.static-locations:在这里配置静态资源路径,
# 这里的配置是覆盖默认配置,所以需要将默认的也加上,
# 否则static、public等这些路径将不能被当作静态资源路径,
# 在这个最末尾的file:${web.upload-path}之所以要加file:是因为指定的是一个具体的硬盘路径,
# 其他的使用classpath指的是系统环境变量。
1、添加jquery和Bootstrap的webjars依赖 如需其他,WebJars查询:https://www.webjars.org/all
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>jqueryartifactId>
<version>3.3.1-1version>
dependency>
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>bootstrapartifactId>
<version>4.2.1version>
dependency>
2、html引入:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="webjars/jquery/3.3.1-1/jquery.js">script>
head>
<body>
<div align="center">
我的第一个springboot应用
div>
<script>
$(function () {
alert("jquery生效")
})
script>
body>
html>
修改tomcat端口和访问路径示例:
server:
port: 8888
servlet:
context-path: /java001
server:
port: 8088
servlet:
context-path: /java001
my_ip: 1.1.1.1
my_port: 9999
@RestController
public class HelloConfigController {
@Value("${server.port}")
String port;
@Value("${my_ip}")
private String ip;
@Value("${my_port}")
private String port;
@GetMapping("/getvalue")
public String getValue() {
return port +","+ ip +","+ port;
}
}
浏览器访问:http://localhost:8088/getvalue
(1)、定义配置文件
userbody:
name: me
password: 123456
birthday: 1992.10.28
mobile: 13812345678
address: 北京市朝阳区
(2)、创建实体类
//需要在实体类上增加注解@ConfigurationProperties,并指定prrfix前缀。
@ConfigurationProperties(prefix="userbody")
public class UserBody {
private String name;
private String password;
private String birthday;
private String mobile;
private String address;
//Setget方法略
}
(3)、编写Controller注入属性bean
@RestController
@EnableConfigurationProperties({UserBody.class})
public class HelloControllerBean {
@Autowired
UserBody userbody;
@GetMapping("/getUser")
public String getUser(){
return userbody.toString();
}
}
浏览器访问:http://localhost:8088/getUser
1、定义test.properties
testuser.name = me
testuser.password = 123
testuser.birthday = 1978.10.28
2、将配置赋值到javabean
@Configuration
@PropertySource("classpath:test.properties")
@ConfigurationProperties(prefix = "testuser")
public class TestUser {
private String name;
private String password;
private String birthday;
//Set get方法略
}
3、Controller 读取配置
@RestController
@EnableConfigurationProperties({TestUser.class})
public class TestController {
@Autowired
TestUser testUser;
@GetMapping("/getUser2")
public String getUser2(){
return testUser.toString();
}
}
浏览器访问:http://localhost:8088/getUser2
创建application-dev.yml:
server:
port: 8003
servlet:
context-path: /java003
创建application-test.yml:
server:
port: 8001
servlet:
context-path: /java001
创建application-prod.yml:
server:
port: 8002
servlet:
context-path: /java002
修改application.yml:active 的值对应不同的{profile}环境
spring:
profiles:
active: test
# 调用application-test.yml的环境配置文件
关于写pojo,和属性注入等,总是需要繁琐又无含量的操作,可以简单的注解形式来简化java代码,提高开发人员的开发效率。
使用步骤:
1、使用maven添加依赖
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.16.18version>
<scope>providedscope>
dependency>
2、添加ide工具对Lombok的支持(本示例为Idea)
注解 | 作用 |
---|---|
@Setter | 注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。 |
@Getter | 注解在类或字段,注解在类时为所有字段生成getter方法,注解在字段上时只为该字段生成getter方法。 |
@ToString | 注解在类,添加toString方法。 |
@EqualsAndHashCode | 注解在类,生成hashCode和equals方法。 |
@NoArgsConstructor | 注解在类,生成无参的构造方法。 |
@AllArgsConstructor | 注解在类,生成包含类中所有字段的构造方法。 |
@RequiredArgsConstructor | 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。 |
@Data | 作用于类上,生成所有属性的get和set方法、toString 方法、hashCode方法、equals方法 |
在pojo上的简单使用:
import lombok.Data;
@Data
public class User {
private int id;
private String name;
}
在调度层上的简单使用
@RestController
@RequestMapping(value="/person")
@AllArgsConstructor(onConstructor_ ={@Autowired} ) //相当于对属性进行了注入
public class PersonController {
//类上面有这句话 @AllArgsConstructor(onConstructor_ ={@Autowired} )
// 属性 就不用再写这个 @Autowired
// @Autowired
PersonDao personDao;
@RequestMapping("/add")
public Person add(){
Person person = new Person();
person.setName("sss");
person.setAge(222);
Person save = personDao.save(person);
return save;
}
}
注解 | 作用 |
---|---|
@Entity | 声明类为实体或表,@Entity 说明这个 class 是实体类,默认 class 名即数据库表中表名,也可以指定表名: @Entity(name=“ss”) 用来指定映射的表名(但不建议使用该方式) |
@Table | 声明表名,@Table 注解指定了 Entity 所要映射带数据库表,其中 @Table(name=“ss”) 用来指定映射表的表名(指定表名建议使用这种方式)。存在表名优先级:@Table > @Entity |
@Basic | 指定非约束明确的各个字段 |
@Embedded | 指定类或它的值是一个可嵌入的类的实例的实体的属性 |
@Id | 指定的类的属性,用于识别(一个表中的主键) |
@GeneratedValue | 指定如何标识属性可以被初始化,例如自动、手动、或从序列表中获得的值,默认值是自动,相当于sql的主键的自增概念 |
@Transient | 指定的属性,它是不持久的,即:该值永远不会存储在数据库中 |
@Column | 指定持久属性栏属性 |
@SequenceGenerator | 指定在@GeneratedValue注解中指定的属性的值。它创建了一个序列 |
@TableGenerator | 指定在@GeneratedValue批注指定属性的值发生器。它创造了的值生成的表 |
@AccessType | 这种类型的注释用于设置访问类型。如果设置@AccessType(FIELD),则可以直接访问变量并且不需要getter和setter,但必须为public。如果设置@AccessType(PROPERTY),通过getter和setter方法访问Entity的变量 |
@JoinColumn | 指定一个实体组织或实体的集合。这是用在多对一和一对多关联 |
@UniqueConstraint | 指定的字段和用于主要或辅助表的唯一约束 |
@ColumnResult | 参考使用select子句的SQL查询中的列名 |
@ManyToMany | 定义了连接表之间的多对多一对多的关系 |
@ManyToOne | 定义了连接表之间的多对一的关系 |
@OneToMany | 定义了连接表之间存在一个一对多的关系 |
@OneToOne | 定义了连接表之间有一个一对一的关系 |
@NamedQueries | 指定命名查询的列表 |
@NamedQuery | 指定使用静态名称的查询 |
1、添加jpa依赖以及mysql、jdbc驱动、连接池druid驱动
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.10version>
dependency>
2、修改springboot配置文件application-dev.yml增加如下jpa配置:配置数据源 账号密码等
spring:
datasource:
url: jdbc:mysql://localhost:3306/springboot-001?serverTimezone=GMT%2B8
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
3、在application.yml中加载dev环境的配置文件
spring:
profiles:
active: dev
4、创建实体
import lombok.*;
import javax.persistence.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "tb_Person")//指定表名为 tb_Person 若默认使用类名作为表名 不用加 @Table 注解
public class Person {
@Id //声明为主键
@GeneratedValue //设置自动增长,+1
private Long id;
//字段标注 @Column name默认不写就是属性名和字段名一致。 nullable是否可为空 length长度
@Column(name = "name", nullable = true, length = 20)
private String name;
@Column(name = "age", nullable = true, length = 4)
private int age;
}
5、新建数据访问接口
///*JpaRepository 实体类的类型:Person,主键的类型:Long*/
public interface PersonDao extends JpaRepository<Person, Long> {
}
6、创建Controller
import com.example.jpademo.dao.PersonDao;
import com.example.jpademo.pojo.Person;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping(value="/person")
public class PersonController {
@Autowired
PersonDao personDao;
@RequestMapping("/add")
public Person add(){
Person person = new Person();
person.setName("sss");
person.setAge(222);
Person save = personDao.save(person);
return save;
}
@RequestMapping("/delete/{id}")
public void delete(@PathVariable Long id){
personDao.deleteById(id);
}
@RequestMapping("/update/{id}")
public void update(@PathVariable Long id){
Person person = personDao.findById(id).get();
person.setName("教育");
personDao.save(person); //没有主键 id,调用该方法就为添加,有id的,就为修改
}
@RequestMapping("/findAll")
public List<Person> findAll(){
return personDao.findAll();
}
}
7、测试数据
8、再修改Person添加属性
@Column(name = "password", nullable = true, length = 20)
private String password;
9、重启工程,person表会更新出password字段。
public interface PersonDao extends JpaRepository<Person, Long> {
//查询指定用户姓名的用户
public Person findByNameIs(String name);
//查询指定用户姓名和密码都相同的用户
public Person findByNameIsAndPassword(String name,String password);
//查询包含指定名字的用户
public List<Person> findByNameContaining(String name);
}
2、新增Controller 类Person2Controller
@RestController
@RequestMapping("/person2")
public class Person2Controller {
@Autowired
PersonDao personDao;
@GetMapping("findByNameIs/{name}")
public Person findByNameIs(@PathVariable String name) {
return personDao.findByNameIs(name);
}
@GetMapping("findByNameIsAndPassword/{name}/{password}")
public Person findByNameIsAndPassword(@PathVariable String name,
@PathVariable String password) {
return personDao.findByNameIsAndPassword(name, password);
}
@GetMapping("findByNameContaining/{name}")
public List<Person> findByNameContaining(@PathVariable String name) {
return personDao.findByNameContaining(name);
}
}
4、测试
1、编辑PersonDao,新增如下方法
//查询指定用户姓名的用户 使用名字参数查询
@Query("select p from Person p where p.name=:name") //这是JPQL语句
public Person getPerson(@Param("name") String name);
//用户登录验证(多个参数的写法) 使用位置参数查询
@Query("select p from Person p where p.name=?1 and p.password=?2")
Public Person login(@Param("name") String name,@Param("password") String password);
//模糊查询用户名里面包含指定字符
@Query("select p from Person p where p.name like %:name%")
public List<Person> getNamesLike(@Param("name") String name);
//查询密码是5位数的全部用户 使用原始sql查询
@Query(value="select * from person where length(password)=5",nativeQuery=true) //使用原始sql
public List<Person> getPasswordisFive();
示例:
1、编辑PersonDao,新增如下方法
//修改用户名称,使用自定义语句来更新,需要显示声明开启写事务
@Modifying
@Transactional(readOnly = false)
@Query("update Person p set p.name=?2 where p.id=?1")
int UpdateName(Long id,String name);
//删除指定用户用户,需要显示声明开启写事务
@Modifying
@Transactional(readOnly = false)
@Query("delete from Person p where p.name=?1")
int DeleteName(String name);
2、编辑Controller 类Person3Controller新增方法updateName
@PutMapping(path="updateName/{id}/{name}")
public int updateName(@PathVariable Long id,@PathVariable String name) {
return personDao.UpdateName(id,name);
}
@DeleteMapping(path="deleteName/{name}")
public int DeleteName(@PathVariable String name) {
return personDao.DeleteName(name);
}
使用示例:
1、编辑PersonDao,新增如下方法
// 排序查询,返回list集合
List<Person> findByNameContaining(String name, Sort sort);
//分页查询, 查询计算元素总个数、总页数,数据多的情况下,代价是昂贵的
Page<Person> findByNameContaining(String name ,Pageable pageable);
//分页查询,返回的是一个片段,它只知道下一片段或者上一片段是否可用。
Slice<Person> getByNameContaining(String name,Pageable pageable);
2、新增Controller 类Person4Controller
@RestController
@RequestMapping("/person4")
public class Person4Controller {
@Autowired
PersonDao personDao;
//sort指排序方向,asc/desc
@GetMapping("findByNameSort/{sort}/{name}")
public List<Person> findByNameSort(@PathVariable String name,
@PathVariable String sort) {//desc/asc
Sort sort = Sort.by(Sort.Direction.fromString(sort),"id");
return personDao.findByNameContaining(name, sort);
}
@GetMapping("findByNamePage1/{page}/{size}/{sort}/{name}")
public Page<Person> findByNamePage1(@PathVariable String name,
@PathVariable int page, //第几页(0:首页)
@PathVariable int size, //每页条数
@PathVariable String sort) {//排序方向asc、desc
Sort sort = Sort.by(Sort.Direction.fromString(sort),"id");
return personDao.findByNameContaining(name, PageRequest.of(page, size , sort);//先排序后分页
}
@GetMapping("findByNamePage2/{page}/{size}/{sort}/{name}")
public Slice<Person> findByNamePage2(@PathVariable String name,
@PathVariable int page, @PathVariable int size,
@PathVariable String sort) {
Sort sort = Sort.by(Sort.Direction.fromString(sort),"id");
return personDao.getByNameContaining(name, PageRequest.of(page,size,sort);
}
}
1、编辑PersonDao,新增如下方法
//按照name查询并且,按照Id降序排序返回第一条
Person findFirstByNameOrderByIdDesc(String name);
//按照name查询并且,按照Id升序排序返回第一条
Person findTopByNameOrderByIdAsc(String name);
//模糊查询指定用户名称,按照id降序排序返回前10条记录
List<Person> findFirst10ByNameLikeOrderByIdDesc(String name);
//模糊查询指定用户名称,按照id升序排序返回前10条记录
List<Person> findTop10ByNameLikeOrderByIdAsc(String name);
2、新增Controller 类Person5Controller
@RestController
@RequestMapping("/person5")
public class Person5Controller {
@Autowired
PersonRepository personRepository;
@GetMapping("findFirstByNameOrderByIdDesc/{name}")
public Person findFirstByNameOrderByIdDesc(@PathVariable String name) {
return personRepository.findFirstByNameOrderByIdDesc(name);
}
@GetMapping("findFirst10ByNameLikeOrderByIdDesc/{name}")
public List<Person> findFirst10ByNameLikeOrderByIdDesc(@PathVariable String name) {
return personRepository.findFirst10ByNameLikeOrderByIdDesc("%"+name+"%");
}
@GetMapping("findTopByNameOrderByIdAsc/{name}")
public Person findTopByNameOrderByIdAsc(@PathVariable String name) {
return personRepository.findTopByNameOrderByIdAsc(name);
}
@GetMapping("findTop10ByNameLikeOrderByIdAsc/{name}")
public List<Person> findTop10ByNameLikeOrderByIdAsc(@PathVariable String name) {
return personRepository.findTop10ByNameLikeOrderByIdAsc("%"+name+"%");
}
}
1、新建实体Dog
@Entity
@Data
public class Dog {
@Id
@GeneratedValue
private Long id;
private String name;
private Long personId; //personId属于外键字段,记录一方表的主键
}
2、编辑Person添加List dogs
//设置级联操作:
@OneToMany(mappedBy = "personId", cascade = CascadeType.ALL)
private List<Dog> dogs;
3、编辑PersonDao,新增如下方法
@Query("select p from Person p join p.dogs d where p.id=?1")
Person findPerson(@Param("id") Long id);
@Modifying
@Transactional(readOnly = false)
void deleteById(Long id);
4、编辑Controller 类Person5Controller,新增方法
@GetMapping("findPerson/{id}")
public Person findPerson(@PathVariable Long id) {
return personDao.findPerson(id);
}
@GetMapping("deletePerson/{id}")
public void delete(@PathVariable Long id){
personRepository.deleteById(id);
}
5、测试 按id获取用户信息方法findPerson、deletePerson
http://localhost:8080/person5/findPerson/2
http://localhost:8080/person5/deletePerson/2
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
spring:
thymeleaf:
cache: false
@Controller
public class FirstThymeleafController {
/**
* 访问http://localhost:8080/first
* 将数据message填充到templates/index.html
* @param model
* @return
*/
@GetMapping("/first")
public String indexPage(Model model) {
String message = "Hello, Thymeleaf!";
model.addAttribute("message", message);
return "index";
}
}
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页title>
head>
<body>
<h1 th:text="${message}">h1>
body>
html>
spring:
thymeleaf:
cache: false
messages:
encoding: UTF-8
basename: message_zh_CN
title=这是标题
message1=这是消息2
message2=这是消息2
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:text="#{title}">title>
head>
<body>
<h1 th:text="${message}">h1>
body>
html>
@Data
public class User {
private Integer id;
private String name;
private int age;
}
@Controller
public class SecondThymeleafController {
@GetMapping("/second")
public String indexPage(Model model) {
String message = "Hello, Thymeleaf!";
User u = new User();
u.setId(1);
u.setName("tc");
u.setAge(18);
Map<String,Object> map=new HashMap<>();
map.put("src1","1.jpg");
map.put("src2","2.jpg");
model.addAttribute("message", message);
model.addAttribute("user", u);
model.addAttribute("src", map);
return "index2";
}
}
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页title>
head>
<body>
<h1 th:text="${message}">h1>
<img th:src="${src.src1}"/>br>
<img th:src="${src.src2}"/>br>
<span th:text="${user.id}">span>
<span th:text="${user.name}">span>
<span th:text="${user.age}">span>
body>
html>
@Controller
public class ThreeThymeleafController {
@GetMapping("/three")
public String indexPage(Model model) {
List<User> list=new ArrayList<User>();
User u1 = new User();
u1.setId(1);
u1.setName("me1");
u1.setAge(18);
list.add(u1);
User u2 = new User();
u2.setId(2);
u2.setName("me2");
u2.setAge(28);
list.add(u2);
User u3 = new User();
u3.setId(3);
u3.setName("me3");
u3.setAge(88);
list.add(u3);
User u4 = new User();
u4.setId(4);
u4.setName("JAVA第一");
u4.setAge(888);
list.add(u4);
model.addAttribute("userList", list);
return "index3";
}
}
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div align="center">
<table cellpadding="10px" cellspacing="0" border="1px solid">
<thead>
<tr>
<th>idth>
<th>nameth>
<th>ageth>
<th>iterStat.indexth>
<th>iterStat.countth>
<th>iterStat.sizeth>
<th>iterStat.currentth>
<th>iterStat.eventh>
<th>iterStat.oddth>
<th>iterStat.firstth>
<th>iterStat.lastth>
tr>
<tr th:each="user,iterStat:${userList}">
<td th:text="${user.id}">td>
<td th:text="${user.name}">td>
<td th:text="${user.age}">td>
<td th:text="${iterStat.index}">indextd>
<td th:text="${iterStat.count}">counttd>
<td th:text="${iterStat.size}">sizetd>
<td th:text="${iterStat.current}">currenttd>
<td th:text="${iterStat.even}">eventd>
<td th:text="${iterStat.odd}">oddtd>
<td th:text="${iterStat.first}">firsttd>
<td th:text="${iterStat.last}">lasttd>
tr>
thead>
table>
div>
body>
html>
@Controller
public class FourThymeleafController {
@GetMapping("/four")
public String indexPage(Model model) {
model.addAttribute("userName", "优就业");
model.addAttribute("href", "http://www.ujiuye.com");
return "index4";
}
}
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页title>
head>
<body>
<h1 th:text="${userName}">h1>
<input type="text" name="names" th:value="${userName}"/>br>
<span th:text="'欢迎来:'+${userName}+'学习!'">span>br>
body>
html>
@Controller
public class FiveThymeleafController {
@GetMapping("/five")
public String indexPage(Model model) {
model.addAttribute("flag", "yes");
model.addAttribute("menu", "admin");
return "index5";
}
}
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div align="center">
<h1 th:if="${flag=='yes'}" >111h1>
<h1 th:unless="${flag=='no'}" >2222h1>
<div th:switch="${menu}">
<p th:case="'admin'">User is an administratorp>
<p th:case="'manager'">User is a managerp>
div>
div>
body>
html>
<link rel="stylesheet" type="text/css" media="all" href="/css/gtvg.css" th:href="@{/css/gtvg.css}" />
<script src="/js/jquery1.42.min.js" th:src="@{/js/jquery1.42.min.js}">script>
示例:
<body>
<h1 th:fragment="copy">
© 1999-2018 Offcn.All Rights Reserved
</h1>
</body>
@Controller
public class SixThymeleafController {
@GetMapping("/six")
public String indexPage(Model model) {
return "index6";
}
}
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页title>
head>
<body>
<div th:insert="~{footer :: copy}">div>br>
<div th:replace="~{footer :: copy}">div>br>
<div th:include="~{footer :: copy}">div>
body>
html>
示例:
@Controller
public class SevenThymeleafController {
@GetMapping("/seven")
public String indexPage(Model model) {
//日期时间
Date date = new Date();
//小数的金额
double price=128.5678D;
//长文本
String str1="一二三四五六七八九十1234567890";
//定义字符串
String str2="JAVA--idea";
model.addAttribute("date", date);
model.addAttribute("price", price);
model.addAttribute("str1", str1);
model.addAttribute("str2", str2);
return "index7";
}
}
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
时间:<span th:text="${#dates.format(date,'yyyy-MM-dd HH:mm:ss')}">2008</span></br>
金额:<span th:text="'¥'+${#numbers.formatDecimal(price,1,2)}">10.00</span> </br>
<!-- str1+(...)一共显示5位,其中后三位固定显示"...",显示的位数少于3就报错! -->
<p th:text="${#strings.abbreviate(str1,5)}">内容内容内容</p>
<!-- 判断字符串是否为空 -->
<span th:if="${!#strings.isEmpty(str2)}">字符串str2不为空</span></br>
<!-- 截取字符串,指定长度 -->
<span th:text="${#strings.substring(str2,0,4)}">字符串str2的值</span>
</body>
</html>
示例:
#声明要连接的数据库地址
spring.datasource.url=jdbc:mysql://localhost:3306/jpadb?serverTimezone=GMT%2b8
#数据库的账号
spring.datasource.username=root
#数据库的密码
spring.datasource.password=root
#数据库的驱动
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 自动创建、更新、验证数据库表结构
spring.jpa.hibernate.ddl-auto=update
# 打印sql语句
spring.jpa.show-sql=true
# thymeleaf设置:禁用模板缓存
spring.thymeleaf.cache=false
@Data
@Entity
@Table(name = "tb_user")//设置数据库表名
public class User {
@Id
@GeneratedValue
private Long id;
@Column(name = "name", nullable = true, length = 200)
private String name;
@Column(name = "age", nullable = true, length = 4)
private Integer age;
}
public interface UserDao extends JpaRepository<User,Long> {
}
//用户数据操作业务接口
public interface UserService {
//获取全部用户数据
public List<User> getUserList();
//新增用户数据
public void createUser(User user);
//获取指定id用户信息
public User getUser(Long id);
//更新指定id用户信息
public void updateUser(Long id,User user);
//删除指定id用户
public void deleteUser(Long id);
}
@Service
@AllArgsConstructor(onConstructor_ ={@Autowired} )
public class UserServiceImpl implements UserService {
UserDao userDao;
@Override
public List<User> getUserList() {
return userDao.findAll();
}
@Override
public void createUser(User user) {
userDao.save(user);
}
@Override
public User getUser(Long id) {
User user = userDao.getOne(id);
// User user1 = userDao.findById(id).get(); //等价findOne()
return user;
}
@Override
public void updateUser(Long id, User user) {
user.setId(id);
userDao.saveAndFlush(user);
}
@Override
public void deleteUser(Long id) {
userDao.deleteById(id);
}
}
@Controller
@RequestMapping("/manageruser")
@AllArgsConstructor(onConstructor_ ={@Autowired} )
public class UserController {
UserService userService;
/***
* 获取全部用户信息
* @return
*/
@GetMapping("/getUserList")
public String getUserList(Model model){
List<User> list = userService.getUserList();
model.addAttribute("page", list);
return "user/list"; //转发到user/list模板
}
/***
* 跳转到新增用户界面
* @return
*/
@RequestMapping("/toAdd")
public String toadd(){
return "user/userAdd";//跳转到userAdd.html
}
/***
* 新增用户
* @param user
* @return
*/
@PostMapping("/add")
public String createUser(User user) {
userService.createUser(user);
return "redirect:/manageruser/getUserList";//重定向到getUserList
}
/***
* 回显
*/
@RequestMapping("/toEdit/{id}")
public String toEdit(Model model,@PathVariable("id")Long id){
User user = userService.getUser(id);
model.addAttribute("user",user);
return "user/userEdit"; //跳转到userEdit.html页面
}
/***
* 修改后保存
*/
@RequestMapping("/edit")
public String edit(User user){
userService.updateUser(user.getId(), user);
return "redirect:/manageruser/getUserList";//获取列表数据并显示
}
/***
* 删除指定id用户
* @param id
* @return
*/
@GetMapping("/delete/{id}")
public String deleteUser(@PathVariable("id") Long id) {
userService.deleteUser(id);
return "redirect:/manageruser/getUserList";
}
}
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>bootstrapartifactId>
<version>4.2.1version>
dependency>
(1)myfragment.html:
<h1 th:fragment="head" align="center">用户管理系统h1>
<h1 th:fragment="foot">
© 1999-2018 Offcn.All Rights Reserved
h1>
(2)list.html:
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>userListtitle>
<link rel='stylesheet' th:href="@{/webjars/bootstrap/4.2.1/css/bootstrap.min.css}" href='webjars/bootstrap/4.2.1/css/bootstrap.min.css'>
head>
<body class="container">
<div th:insert="~{user/myfragment :: head}">div><br/>
<h1>用户列表h1><br/><br/>
<div class="with:80%">
<div class="form-group">
<div class="col-sm-2 control-label">
<a href="toAdd" th:href="@{toAdd}" class="btn btn-info">adda>
div>
div>
<table class="table table-hover">
<thead>
<tr>
<th>#th>
<th>Nameth>
<th>Ageth>
<th>Editth>
<th>Deleteth>
tr>
thead>
<tbody>
<tr th:each="user : ${page}">
<th scope="row" th:text="${user.id}">1th>
<td th:text="${user.name}">neotd>
<td th:text="${user.age}">6td>
<td><a th:href="@{'toEdit/'+${user.id}}">edita>td>
<td><a th:href="@{'delete/'+${user.id}}">deletea>td>
tr>
tbody>
table>
div>
<div th:include="~{user/myfragment :: foot}">div>
body>
html>
(3)userAdd.html
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>usertitle>
<link rel='stylesheet' th:href="@{/webjars/bootstrap/4.2.1/css/bootstrap.min.css}" href='webjars/bootstrap/4.2.1/css/bootstrap.min.css'>
head>
<body class="container">
<div th:insert="~{user/myfragment :: head}">div>
<br/>
<h1>添加用户h1>
<br/><br/>
<div class="with:80%">
<form class="form-horizontal" th:action="@{add}" method="post">
<div class="form-group">
<label for="name" class="col-sm-2 control-label">namelabel>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" id="name" placeholder="name"/>
div>
div>
<div class="form-group">
<label for="age" class="col-sm-2 control-label">agelabel>
<div class="col-sm-10">
<input type="text" class="form-control" name="age" id="age" placeholder="age"/>
div>
div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="submit" value="Submit" class="btn btn-info" />
<input type="reset" value="Reset" class="btn btn-info" />
div>
div>
form>
div>
<div th:include="~{user/myfragment :: foot}">div>
body>
html>
(4)userEdit.html
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>usertitle>
<link rel='stylesheet' th:href="@{/webjars/bootstrap/4.2.1/css/bootstrap.min.css}" href='webjars/bootstrap/4.2.1/css/bootstrap.min.css'>
head>
<body class="container">
<div th:insert="~{user/myfragment :: head}">div>
<br/>
<h1>修改用户h1>
<br/><br/>
<div class="with:80%">
<form class="form-horizontal" th:action="@{/manageruser/edit}" th:object="${user}" method="post">
<input type="hidden" name="id" th:value="*{id}" />
<div class="form-group">
<label for="name" class="col-sm-2 control-label">namelabel>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" id="name" th:value="*{name}" placeholder="name"/>
div>
div>
<div class="form-group">
<label for="age" class="col-sm-2 control-label">agelabel>
<div class="col-sm-10">
<input type="text" class="form-control" name="age" id="age" th:value="*{age}" placeholder="age"/>
div>
div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="submit" value="Submit" class="btn btn-info" />
<a href="/manageruser/" th:href="@{/manageruser/}" class="btn btn-info">Backa>
div>
div>
form>
div>
<div th:include="~{user/myfragment :: foot}">div>
body>
html>
9、运行测试:http://localhost:8080/manageruser/getUserList(需要添加信息,列表才有显示)
这样就统一了数据操作的接口,仅通过不同的HTTP方法,就可以完成对数据的所有增删查改工作
使用示例:
@RestController
@Validated //开启数据有效性校验,添加在类上即为验证方法,/// 添加在方法参数中即为验证参数对象。
public class UserController {
@Autowired
private UserService userService;
// @GetMapping("/getUser")
// @PutMapping
// @DeleteMapping
// @PostMapping
// @PatchMapping
@RequestMapping("/getUser")
public String getUser() {
return userService.getUserName();
}
@GetMapping("/user/{id:[\\w_]+}")
public String getUserById(@PathVariable String id){
return "根据id查询用户:"+id;
}
@GetMapping("/user")
public String getAllUser(){
return "查询所有用户";
}
@DeleteMapping("/user/{id}")
public String deleteById(@PathVariable String id){
return "根据id删除:"+id;
}
@DeleteMapping("/user")
public String deleteAll(){
return "删除所有";
}
@PostMapping("/user")
public User add(@RequestBody User user){ //不加@RequestBody 就模拟表单传输
return user;
}
@PutMapping("/user")
public User update(@RequestBody User user){
return user;
}
@GetMapping("/demo123")
public String user(@NotBlank(message = "id不能为空!") @RequestParam("userid") String id,
@NotBlank(message = "name不能为空!") @RequestParam("username") String name,
@Email(message = "email格式不正确!") String email){
return id+"==》"+name+email;
}
}
注解 | 作用 |
---|---|
@Api() | 用于类,表示标识这个类是swagger的资源 |
@ApiOperation() | 用于方法,表示一个http请求的操作 |
@ApiParam() | 用于方法,参数,字段说明,表示对参数的添加元数据(说明或是否必填等) |
@ApiModel() | 用于类,表示对类进行说明,用于参数用实体类接收 |
@ApiModelProperty() | 用于方法,字段,表示对model属性的说明或者数据操作更改 |
@ApiIgnore() | 用于类,方法,方法参数 ,表示这个方法或者类被忽略 |
@ApiImplicitParam() | 用于方法 ,表示单独的请求参数 |
@ApiImplicitParams() | 用于方法,包含多个 @ApiImplicitParam |
使用示例:
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
@Configuration
@EnableSwagger2 //生成api文档
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//这里需要注意,需要指定那些需要生成api文档的controller。 com.example.jpademo.controller
.apis(RequestHandlerSelectors.basePackage("com.example.jpademo.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("优乐选项目api文档")
.description("项目组-001")
.termsOfServiceUrl("http://www.ujiuye.com/")
.contact(new Contact("作者:tcy","xxxx.com","[email protected]"))
.version("version:1.0")
.build();
}
}
@RestController
@Api(tags = "用户接口")//tags="说明该类的作用"
public class UserController {
/**
* 新增用户
* @param user
* @return
*/
@ApiOperation(value="新增", notes="新增用户信息")/*value="说明方法的作用" notes="方法的备注说明"*/
@ApiImplicitParams({
@ApiImplicitParam(name = "user", value = "用户实体对象", dataType = "User"),/*方法参数说明*/
@ApiImplicitParam(name = "id", value = "用户id", dataType = "Integer")
})
@PostMapping("/user")
public String createUser(User user,Integer id) {
return "success-添加成功";
}
/***
* 根据id删除用户
* @param id
* @return
*/
@ApiOperation(value="删除", notes="根据用户id删除")/*value="说明方法的作用" notes="方法的备注说明"*/
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "用户id", required = true, dataType = "Long")
})
@DeleteMapping("/user/{id}")
public String deleteUser(@PathVariable("id") Long id) {
return "success-删除成功";
}
/**
* 更新用户信息
* @return
*/
@ApiOperation(value="更新", notes="更新用户信息")/*value="说明方法的作用" notes="方法的备注说明"*/
@ApiImplicitParams({
@ApiImplicitParam(name = "user", value = "需要更新的用户实体", dataType = "User")
})
@PutMapping("/user")
public String updateUser(User user) {
return "success-修改成功";
}
}
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.10version>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>1.2.5version>
dependency>
spring:
datasource:
name: datasource
type: com.alibaba.druid.pool.DruidDataSource
#druid相关配置
druid:
#基本属性
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/mybatisdb
?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: root
#监控统计拦截的filters
filters: stat
#配置初始化大小/最小/最大
initial-size: 1
min-idle: 1
max-active: 20
#获取连接等待超时时间
max-wait: 60000
#间隔多久进行一次检测,检测需要关闭的空闲连接
time-between-eviction-runs-millis: 60000
#一个连接在池中最小生存的时间
min-evictable-idle-time-millis: 300000
validation-query: SELECT 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 打开PSCache,并指定每个连接上PSCache的大小。
# oracle设为true,mysql设为false。分库分表较多推荐设置为false
pool-prepared-statements: false
max-pool-prepared-statement-per-connection-size: 20
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.offcn.pojo
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
@Data
public class Employee {
private Integer eid;
private String ename;
}
@SpringBootApplication
//在Springboot01Application上添加 @MapperScan("com.offcn.dao")注解,
//在com.offcn.dao包中扫描Dao接口。
@MapperScan("com.offcn.dao")
public class Springboot01Application {
public static void main(String[] args) {
SpringApplication.run(Springboot01Application.class, args);
}
}
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
<version>2.0.4.RELEASEversion>
dependency>
redis:
host: 192.168.145.128
port: 6379
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-mongodbartifactId>
<version>2.0.4.RELEASEversion>
dependency>
data:
mongodb:
# 账号密码admin:123456 链接路径端口s以及数据库 192.168.145.128:27017
uri: mongodb://admin:[email protected]:27017/mydb