部署Deploy

https://www.cnblogs.com/yfzhou/p/9668366.html
https://blog.csdn.net/qq_36523667/article/details/78584488?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

框架Framework

  • Struts Hibernate
  • Netty
  • Dubbo
  • Spring | 三层架构 MVC模式MVC框架
    Model View Controller 模型-视图-控制器

    视图层 View、表现层
    业务逻辑 服务层 Service,
    与持久层 数据层 DAO
    https://www.jianshu.com/p/8764c9bbc88a | | | | —- | —- | —- |

项目配置

  • 邮箱配置host: “smtp.qq.com”,port: 587,
  • 数据库host port username password

    Java注解

    @PostConstruct@PreConstruct

    Java类称呼

    | Entity类
    data objectBo(business object)Po(persistant object)持久层对象Dto(data transfer object)
    VO
    do domain object | POJO(Plain Ordinary Java Object)即普通Java类,具有一部分getter/setter方法的那种类就可以称作POJO。
    - Javabean
    - ejb Enterprise Java Beans

    | https://www.cnblogs.com/hunmeng/p/11298680.html
    https://www.cnblogs.com/linhuaming/p/9901955.html | | —- | —- | —- |

Servlet容器Container Tomcat

  • 官网https://tomcat.apache.org/

    Servlet小服务程序

    | 类图类型javax.servlet
    javax.servlet.http
    - Servlet接口
    - HttpServlet抽象类 GenericServlet
    - ServletRequestServletResponse接口
    - HttpServletRequest接口
    - HttpSession Cookie
    | 浏览器过程 | | | —- | —- | —- |

Spring

  • Spring事务
  • 官网https://spring.io
  • 环境搭建https://start.spring.io/
    • Group域名的反写
    • Artifact
    • Dependencies选依赖

  • | |
    - Spring用于管理对象
    - Spring MVC是基于 Servlet 的一个 MVC 框架
    - SpringCloud
    - SpringBoot
    由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。 | 参考 | | —- | —- | —- | | 核心包类型
    - SpringApplication run方法
    - ApplicationContext接口
    模块
    - SpringCore
    - SpringContext
    - Beans
    | springboot启动
    |
    - org.springframework.boot
    - spring-boot-starter
    - org.springframework
    |

注解

|
- 启动类@SpringBootApplication组合的
@Configuration
@EnableAutoConfiguration
@ComponentScan
@Filter |
- 声明
- @Component 组件,没有明确的角色
- @Service 在业务逻辑层使用(service层)
- @Repository 在数据访问层使用(dao层)
- @Controller 在展现层使用,控制器的声明
- @Bean创建
- @Scope
|
- 注入
@Autowired
@Inject:由JSR-330提供
@Resource:由JSR-250提供 | | —- | —- | —- | |
- @ModelAttribute用的少
| | |

IOC(InversionOfControl)控制反转

DI(DependencyInjection)依赖注入
- Field字段注入
- Setter注入
- 构造器注入

SpringAOPAspectOrientedProgramming面向切面编程

切面Aspect 切点 代理模式 注解

参考

SpringMVC

表单中有多个相同的字段,以及springmvc接收多个相同对象 SpringMVC数据校验@NotEmpty@NotBlank@NotNull
BindingResult
@Valid表单验证
注解
- 请求Request
- @RequestMapping
- @RequestHeader@RequestBody@RequestParam
- @PathVariable
- 响应Response
- @ResponseBody
- @ModelAttribute
数据模型ModelModelMapModelAndView
https://blog.csdn.net/u013654037/article/details/41944947
Cookie Session HttpSession
@SessionAttributes @CookieValue

SpringBoot

  • thymeleaf
  • AOP
  • springboot单元测试@SpringBootTest @Test | 运行debug模式 支持 热更新 recompare
    https://www.jianshu.com/p/f658fed35786
    https://blog.csdn.net/xiaojin21cen/article/details/88312873
    热部署

    org.springframework.boot
    spring-boot-devtools
    | session

    org.springframework.session
    spring-session-data-redis


    - redis

    org.springframework.boot
    spring-boot-starter-data-redis

    https://blog.csdn.net/xcbeyond/article/details/81116600 | 数据库
    mysql
    mysql-connector-java
    runtime


    org.mybatis.spring.boot
    mybatis-spring-boot-starter
    2.1.0

    #mysql数据库连接配置spring.datasource.url=jdbc:mysql://localhost:3306/campus_transaction?useUnicode=true&characterEncoding=utf8&serverTimezone=GMTspring.datasource.username=rootspring.datasource.password=qasdfGHjklm152 | | —- | —- | —- |

MyBatis

自动生成Mybatis-generator
https://gitee.com/b-match/MyBatis_Generator
1. 打开工程文件
1. 自定义配置
1. 执行文件
1. 复制 粘贴
1. 数据库配置
1. 修改mapper文件 注解
Insert id(如果是自动生成的话去掉) gmt_created gmt_modified now()
update 的 时间
注解
@Results
@ResultMap
@Param
@SelectProvider
@Mapper生成的mapper接口需要

Java工具库

https://blog.csdn.net/jintingbo/article/details/81633615
https://blog.csdn.net/zmemorys/article/details/87275032

  • RedirectView

    错误页面

  • ErrorViewResolver接口

  • web.xml配置

    用户数统计

  • HttpSessionListener接口

  • HttpSessionEvent类

页面控制

  • @Controller
  • 返回值ModelAndView
    1. @Controller
    2. public class Controller
    3. @RequestMapping("/request")
    4. public ModelAndView request() {
    5. ModelAndView mv = new ModelAndView();
    6. //封装要显示到视图的数据
    7. mv.addObject("msg","hello myfirst mvc");
    8. //视图名
    9. mv.setViewName("hello");
    10. return mv;
    11. }
    12. }
  1. @Controller
  2. public class Controller
  3. @RequestMapping("/request")
  4. public ModelAndView request() {
  5. return new ModelAndView("redirect:login.html");;
  6. }
  7. }

返回值String

请求转发

@Controller
public class Controller

   @RequestMapping("/request")
    public String request() {
        return "index";return "index.html";//好像都可以 静态页面写全
    }

}

重定向

@Controller
public class Controller

   @RequestMapping("/request")
    public String request() {
        return "redirect:/index.html"
    }

}

@RestController

@RestController
public class RestController

   @RequestMapping("/request")
    public String request() {
        return "json"
    }

}

response

@Controller
public class Controller

   @RequestMapping("/request")
    public boolean request() {
          response.sendRedirect("/yikao/login.html");
        return true;
    }

}

注意 : 动态页面 和静态页面方式不一样

主页默认会访问 index.html

@Controller
@RequestMapping(“/“)
public class IndexController {
@RequestMapping(“/Blog”)
public String index() {
return “forward:index.html”;
}
}
拦截器
使用功能
拦截 不登陆 直接访问内部资源的 请求


请求转发重定向
返回多媒体参考https://blog.csdn.net/u014449560/article/details/82807517
https://blog.csdn.net/sinat_25484327/article/details/94590439?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task


https://www.cnblogs.com/springforall/p/12143041.html
错误页面

参考https://blog.csdn.net/IT_faquir/article/details/79521417

用户验证

手机验证码

送10块
http://www.miaodiyun.com/
免费
https://www.mob.com/
极光
https://www.jiguang.cn/

图片验证码

依赖

<dependency>
  <groupId>com.github.penggle</groupId>
  <artifactId>kaptcha</artifactId>
  <version>2.3.2</version>
</dependency>

后端

import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;

import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;

import java.util.Properties;

@Controller
public class CaptchaControl {
    生成图片
    @RequestMapping(value = "/captcha")
    public void getCaptcha(HttpSession session, HttpServletResponse response) 
        throws IOException {
        // 设置 HTTP Cache 响应头  让验证码不要有本地catche
        // Set to expire far in the past.
        response.setDateHeader("Expires", 0);
        // Set standard HTTP/1.1 no-cache headers.
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        // Set IE extended HTTP/1.1 no-cache headers (use addHeader).
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        // Set standard HTTP/1.0 no-cache header.
        response.setHeader("Pragma", "no-cache");

        // 设置 HTTP 内容格式
        // return a jpeg
        response.setContentType("image/png");

        // 创建随机数
        // create the text for the image.
        String capText = kaptcha.createText();

        // store the text in the session.
        session.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);
        session.setAttribute("11","111");

        // 输出图片
        // create the image with the text.
        BufferedImage bufferedImage = kaptcha.createImage(capText);
        // write the data out.
        ServletOutputStream outputStream = response.getOutputStream();
        ImageIO.write(bufferedImage, "png", outputStream);
        try {
            outputStream.flush();
        } finally {
            outputStream.close();
        }

    }

    @Autowired
    private DefaultKaptcha kaptcha;
    // 初始化 kaptcha
    @Bean
    public DefaultKaptcha initKaptcha(){
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();

        Properties properties = new Properties();
        //配置验证码
//        properties.put(Constants.KAPTCHA_TEXTPRODUCER_CHAR_STRING, "1234567890");
//        properties.put(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, 5);
//        properties.put(Constants.KAPTCHA_IMAGE_HEIGHT, "44");//不能为小数
//        properties.put(Constants.KAPTCHA_IMAGE_WIDTH, "140");
//        properties.put(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "32");

        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}

前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>验证码</title>
</head>
<body>
    <form action="/signupmock" method="get">
        <div>
            <span>验证码</span>
            <input class="code" type="text" placeholder="" name="code">
            <img onclick="reloadCaptcha()" id="captchimage" class="image" src="/captcha">
        </div>
    </form>
</body>
</html>
<script>
    function reloadCaptcha() {
        var captchimage = document.getElementById("captchimage");
        captchimage.src = "/captcha?t=" + (new Date().getTime());
    }
</script>

参考

配置
https://shimo.im/sheets/USjfERxK5MQyzURV

不刷新图片
https://blog.csdn.net/ganges_zs/article/details/82355883

邮箱验证码

依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

配置

spring.mail.host=smtp.qq.com
spring.mail.username=1424036574@qq.com
spring.mail.password=mnahedlqdzeegiaa

前端

后端

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.impl.DefaultKaptcha;

@Controller
public class EmailControl {
    @Autowired
    private JavaMailSender mailSender;
    @Autowired
    private DefaultKaptcha kaptcha;

    @RequestMapping(value = "/sendmail")
    @ResponseBody
    public String sendmail(HttpSession session,
                       @RequestParam("email")String email){
        //文本格式邮件
        SimpleMailMessage message = new SimpleMailMessage();

        message.setFrom("1424036574@qq.com");
        message.setTo(email);
        message.setSubject("主题:验证码");

        String code = kaptcha.createText();

        session.setAttribute("EmailCode", code);

        message.setText(code);
        mailSender.send(message);

        return "发送成功";
    }

    @RequestMapping(value = "/sendmail")
    @ResponseBody
    public String sendmail(HttpSession session,
                       @RequestParam("email")String email){
        //html邮件
        MimeMessage message = mailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom("1424036574@qq.com");
            helper.setTo(email);
            helper.setSubject("主题:验证码");
            String code = kaptcha.createText();
            session.setAttribute("emailcode", code);
            message.setText("<h1>" + code + "</h1>", "utf-8", "html");
            mailSender.send(message);
        } catch (MessagingException e) {
            e.printStackTrace();
        }
        return "发送成功";
    }

}

前端

用户登录鉴权

步骤

image.png

创建方法注解

import java.lang.annotation.*;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface NeedLogin {
}

添加自定义拦截器

import com.yikao.model.User;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@Component
public class AuthHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) throws Exception {
        if(handler instanceof HandlerMethod){
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            NeedLogin needLogin = handlerMethod.getMethodAnnotation(NeedLogin.class);
            if(needLogin != null){
                User user = (User) request.getSession().getAttribute("user");
                if(user == null){
                    response.sendRedirect("/yikao/login.html");
                    return false;
                }
            }
        }
        return true;
    }
}

注册拦截器

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//注册拦截器
@Configuration
public class LoginWebMvcConfigurer implements WebMvcConfigurer {
    @Autowired
    private AuthHandlerInterceptor authHandlerInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authHandlerInterceptor).addPathPatterns("/**");
    }
}

测试

@Controller
public class LoginControl {
    @RequestMapping(path = "/login")
    public String loginSuccess(HttpSession session,User user) {
        session.setAttribute("ueser",user);
        return "index.html";
    }

    @RequestMapping(path = "/login")
    @NeedLogin
    public String request() {
        return "index.html";
    }

    @RequestMapping(path = "/logOut")
    public String logOut(HttpSession session) {
        session.removeAttribute("ueser",user);
        return "login.html";
    }
}

会话状态HttpCookie

|
-

  • 属性
    - 作用域 设置域名setDomain 路径
    如果你是次级域名 设置顶级域名 其它次级域名 都可以访问
    https://segmentfault.com/a/1190000006932934
    - 有效期 路径
    - 过期时间 (相对过期过期时间 是 cookie写入以后开始计算)
    - 前端能否修改
    - 属性默认值
    有效期 默认 1969-12-31 但是浏览器关闭 就没有了
    路径 是请求路径
    域名 默认当前域名 |

    注解

    @CookieValue(name = “name”,required = false) |

    浏览器查看

    application
    image.png
    也可以在 network查看 某一个请求响应的 cookie | | —- | —- | —- |

HttpSession

| 概念
- session 会话 抽象概念 一种用户状态的解决方案
- 具体session的实现是 存在服务端的一个数据结构
- session借助cookie来实现 cookie 存储 sessionID 不用cookie 也可以
- 作用一样
- cookie 有很多缺点 主要是大小限制 还能被用户看到
- 存的用户信息不同
- 关系 : HashMap() 我是这么认为的
- session比cookie 代码操作方便
|
- 这个id 在会话 过期之前 是不会变得 你可以软件操作 或者根据软件设置的过期时间
- 修改了 sessionID 就get不了 session里面的其他数据了
- 不同浏览器有不同的session
| 浏览器查看
- cookie存储sessionid
image.png
-


| | —- | —- | —- | | 属性设置默认30分钟
#spring.session.timeout=15 //过期时间 单位秒注解
@SessionAttribute(value = “msg”, required = false) | 问题如果seesionid 被盗取了了 很危险
- 普通用户 我自己登陆的
image.png
- 黑客的
image.png
- 解决 token
- 参考https://www.zhihu.com/question/19786827/answer/84540780
| |

RedisSession

作用分布式
高可用依赖

org.springframework.session—>
spring-session-data-redis—>


org.springframework.boot—>
spring-boot-starter-data-redis—>
配置
# Redis服务器地址:
spring.redis.host=r-student.redis.rds.aliyuncs.com
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=Bmatch123对象序列化
public class User implements Serializable {
}