这里写自定义目录标题
阶段
现在是2020年3月26日13:57:16,看看我要学多久_(:з」∠)_
狂神笔记
helloWorld
1 ,改端口号
- 在application.properties中加入
#更改端口号
server.port=8080
2,自定义banner
https://www.bootschool.net/ascii
将banner.txt导入resource中
自动装配原理
- 启动器
想要什么功能就导入相关的启动器 - pom.xml
yaml配置注入
-
书写格式
-
@ConfigurationProperties(prefix = “”) //引入yaml
-
@PropertySource(value = "classpath : qinjiang. properties ")//引入
-
JSR303数据校验-@Validated()
-
松散绑定
exp: last-name – lastName
多环境配置及配置文件的目录
- 配置文件的优先级
- 环境选择
自动装配原理
- 1、SpringBoot启动会加载大量的自动配置类
@Configuration
- 2、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
@ConditionalOnClass({…}) 判断该类是否存在
- 3、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)
@EnableConfigurationProperties({…class})
- 4、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
xxxxAutoConfigurartion:自动配置类;给容器中添加组件
xxxxProperties:封装配置文件中相关属性;
静态资源引入
- webjars
导入静态文件
属于:WebMvcAutoConfiguration这个类
- 一共有四个位置可以选
“classpath:/META-INF/resources/”,…/webjars/…
“classpath:/resources/”,
“classpath:/static/”,
“classpath:/public/”
优先级从低到高
如果自定义静态文件路劲
spring.mvc.static-path-pattern=
默认得配置会失效—不建议这么做
首页
将文件放在public,static,或者resources文件夹中
模板引擎
初试
- 后缀要是 **.html
- 导入jar包
- 在templates文件下新建文件 (a.html)
- 编写controller
@Controller
public class TestController {
@RequestMapping(value = "/test",method = RequestMethod.GET)
public String goA(Model model){
model.addAttribute("msg","hello,springboot");
return "a";
}
}
thymeleaf基础语法
- 链接:th:href — @{}
- messages:#{}
实例一
i18n
源码:
- **.properties
- **_zh_CN.properties
- **_en_US.properties
在application.yml中
spring:
messages:
basename: i18n.login #配置文件的真实路径
- MyLocaleResolver
public class MyLocaleResolver implements LocaleResolver {
//解析请求
@Override
public Locale resolveLocale(HttpServletRequest request) {
String l = request.getParameter("l");
Locale locale = Locale.getDefault();//没有就使用默认的
if (!StringUtils.isEmpty(l)){
String[] split = l.split("_");//得到国家 地区
locale = new Locale(split[0], split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
- MyMvcConfig
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("index.html").setViewName("index");
}
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
}
- index.html
<a class="btn btn-sm" th:href="@{/index.html(l=zh_CN)}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l=en_US)}">English</a>
拦截器
- LoginController
@Controller
public class LoginController {
@RequestMapping(value = "/login")
public String login(@RequestParam("username") String username,
@RequestParam("password") String password ,
Model model,
HttpSession session){
if (!StringUtils.isEmpty(username)&&password.equals("123")){
session.setAttribute("name",username);
return "redirect:/main.html";
}else {
model.addAttribute("msg","账户密码错误!");
return "index";
}
}
}
- LoginHandlerInterceptor 实现 HandlerInterceptor 重写preHandle()
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String name = (String) request.getSession().getAttribute("name");
if (StringUtils.isEmpty(name)){
request.setAttribute("msg","没有权限,请先登录~~");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else {
return true;
}
}
}
- MyMvcConfig - 重写addInterceptors()
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("index.html").setViewName("index");
registry.addViewController("main.html").setViewName("dashboard");
}
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**").excludePathPatterns("/index.html","/","/login","/asserts/**");
}
}
提取公共模块
<div th:replace="~{commons/commons::topbar}"></div>
列表展示
- <'tr th:each=“emp:${list}”>
- ${#dates.format(emp.getBirth(),‘yyyy-MM-dd HH:mm:ss’)}
<thead>
<tr>
<th>id</th>
<th>lastName</th>
<th>email</th>
<th>gender</th>
<th>departmentName</th>
<th>birth</th>
<th>option</th>
</tr>
</thead>
<tbody>
<tr th:each="emp:${list}">
<td th:text="${emp.getId()}"></td>
<td th:text="${emp.getLastName()}"></td>
<td th:text="${emp.getEmail()}"></td>
<td th:text="${emp.getGender()==0?'女':'男'}"></td>
<td th:text="${emp.getDepartment().getDepartmentName()}"></td>
<td th:text="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}"></td>
<td>
<button class="btn btn-sm btn-primary">编辑</button>
<button class="btn btn-sm btn-danger">删除</button>
</td>
</tr>
</tbody>
添加功能
- data 的格式
可以修改
spring:
mvc:
date-format: yyyy/MM/dd
@PostMapping("/emp")
public String add(Employee employee){
System.out.println(employee);
employeeDao.save(employee);
return "redirect:/emps";
}
修改功能
- 数据回显
<input class="form-check-input" type="radio" name="gender" value="1" th:checked="${emp.getGender()==1}">
...
<!--提交的是部门的id-->
<select class="form-control" name="department.id">
<option th:value="${dept.id}" th:each="dept:${deps}" th:text="${dept.departmentName}"
th:selected="${emp.getDepartment().getId()==dept.getId()}">1
</option>
</select>
...
<input name="birth" type="text" class="form-control" placeholder="yyyy/MM/dd" th:value="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}">
删除功能-没有用到RESTful
@GetMapping("/delete/{id}")
public String delete(@PathVariable("id") Integer id){
employeeDao.delete(id);
return "redirect:/emps";
}
注销登录
@GetMapping("/logout")
public String logout(HttpSession session){
session.invalidate();
return "redirect:/login";
}
JDBC
整合Druid数据源
整合MyBatis
- 项目结构
1,application.yaml
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC&userUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
type-aliases-package: com.wu.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
2,Flower
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Flower {
private Integer id;
private String name;
private Double price;
private String production;
}
3,FlowerMapper
@Mapper //这是一个 mybatis 的 mapper 类
@Repository //持久层
public interface FlowerMapper {
List<Flower> queryFlowerList();
}
4,FlowerMapper .xml
<mapper namespace="com.wu.spring.mapper.FlowerMapper">
<select id="queryFlowerList" resultType="com.wu.spring.pojo.Flower">
select * from flower;
</select>
</mapper>
5,FlowerController
@Controller
public class FlowerController {
@Autowired
private FlowerMapper flowerMapper;
@ResponseBody
@GetMapping("/queryFlowerList")
public List<Flower> queryFlowerList(){
List<Flower> flowers = flowerMapper.queryFlowerList();
for (Flower flower:flowers){
System.out.println(flower);
}
return flowers;
}
}
SpringSecurity
- 清除thymeleaf缓存
spring:
thymeleaf:
cache: false
- 默认导入包后 不添加配置,都会跳到 login.html-默认配置
授权— protected void configure(HttpSecurity http)
- 注销
HttpSecurity
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//1.所有人都可以访问首页
//2.请求授权的规则
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1") //路径-角色
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
//还没登录自动跳转到登录页
http.formLogin();
//注销,开启注销功能,跳到首页
http.logout().logoutSuccessUrl("/");
}
认证— protected void configure(AuthenticationManagerBuilder auth)
- 有关加密的类
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//内存中
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("wu").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3");
}
Shiro
环境搭建
- 导入jar
- 编写配置类
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
- UserRealm
public class UserRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("授权--doGetAuthorizationInfo");
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("认证--doGetAuthenticationInfo");
return null;
}
}
- ShiroConfig
@Configuration
public class ShiroConfig {
//第三步 :安全管理器
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager manager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(manager);
return shiroFilterFactoryBean;
}
//第二步,管理
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
//第一步,创建realm对象,需要自定义类;用户
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
Shiro整合Mybatis
Swagger
1,简单配置
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
Contact contact = new Contact("Mr-Jies", "https://blog.csdn.net/weixin_43523875", "2306156172@qq.com");
return new ApiInfo(
"Mr-Jies的 Documentation",
"远寻自己的鲸鱼!",
"1.0",
"https://blog.csdn.net/weixin_43523875",
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList<VendorExtension>());
}
}
2,配置扫描接口
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//扫描全部
// .apis(RequestHandlerSelectors.any())
//扫描指定的包
// .apis(RequestHandlerSelectors.basePackage("com.wu.springboot"))
//不扫描
// .apis(RequestHandlerSelectors.none())
//扫描ClassAnnotation 类注解
.apis(RequestHandlerSelectors.withClassAnnotation(Controller.class))
//扫描方法注解
// .apis(RequestHandlerSelectors.withMethodAnnotation(RequestMapping.class))
//paths-指定条件
.paths(PathSelectors.none())
.build();
}
3,是否启动swagger
@Bean
public Docket docket(){
//设置要显示的swagger环境
Profiles profiles = Profiles.of("dev", "test");
//通过environment.acceptsProfiles 判断是否处于自己设定的环境中
boolean b = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
//是否启动swagger
.enable(b)
.select() //select与build配套使用
.apis(RequestHandlerSelectors.withClassAnnotation(Controller.class))
.paths(PathSelectors.none())
.build();
}
4,分组
- groupName();
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("As");
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("Bs");
}
@Bean
public Docket docket3(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("Cs");
}
}
5,接口注释
- User
@ApiModel("User类")
public class User {
@ApiModelProperty("姓名")
private String name;
@ApiModelProperty("地址")
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User() {
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public User(String name, String address) {
this.name = name;
this.address = address;
}
}
- HelloController
@Api("hello控制类")
@Controller
public class HelloController {
@ResponseBody
@GetMapping("/hello")
public String hello(){
return "你好swagger!";
}
@ResponseBody
@ApiOperation(value = "user控制-get",notes="获取单个user,需参数", httpMethod = "GET")
@GetMapping("/user")
public User user(String name,String address){
return new User(name,address);
}
@ResponseBody
@ApiOperation(value = "user控制-get",notes="获取单个user,需参数", httpMethod = "GET")
@GetMapping("/user3")
public User user3(User user){
return user;
}
@ResponseBody
@ApiOperation(value = "user控制-post",notes="获取单个user,需参数", httpMethod = "POST")
@PostMapping("/user2")
public User user2(String name, String address){
// int i = 5/0;
return new User(name,address);
}
@ResponseBody
@ApiOperation(value = "user控制-post",notes="获取单个user,需参数", httpMethod = "POST")
@PostMapping("/user4")
public User user4(@ApiParam User user){
// int i = 5/0;
return user;
}
}
总结
邮件发送
2个test
- 简单的
- 复杂的
@SpringBootTest
class SpringboorApplicationTests {
@Autowired
JavaMailSenderImpl mailSender;
@Test
void contextLoads() {
SimpleMailMessage message = new SimpleMailMessage();
message.setSubject("通知");
message.setText("你好呀!Mr-Jies");
message.setTo("2306156172@qq.com");
message.setFrom("2306156172@qq.com");
mailSender.send(message);
}
@Test
void contextLoads2() throws MessagingException {
//发送一个复杂的邮件
//复杂的邮件
MimeMessage mimeMessage = mailSender.createMimeMessage();
//组装
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
//正文
helper.setSubject("你好呀Mr-Jies");//标题
helper.setText("<p style='color:red'>这是我的docx和jpg</p>",true);
//附件
helper.addAttachment("2-26.docx", new File("D:\\Desktop\\2-26.docx"));
helper.addAttachment("12.jpg", new File("D:\\Desktop\\12.jpg"));
helper.setTo("2306156172@qq.com");
helper.setFrom("2306156172@qq.com");
mailSender.send(mimeMessage);
}
}
- qq邮箱要开启POP3/SMTP服务
- 配置文件 yaml
spring:
mail:
username: 2306156172@qq.com
password: ---POP3/SMTP服务密码----
host: smtp.qq.com
##开启加密授权
properties.mail.smtp.ssl.enable: true
定时任务
- 在application main中声明
@Async //支持异步操作
@EnableScheduling //开启定时功能
- spring容器会自动执行 不需加其他操作
@Service
public class ScheduledService {
//cron表达式:秒 分 时 日 月 星期
@Scheduled(cron = "0/2 * * * * ?")
public void hello(){
System.out.println(new Date());
}
}