美文网首页Javawebspringboot经验
SpringBoot微信点餐系统

SpringBoot微信点餐系统

作者: Tommmmm | 来源:发表于2018-08-27 21:34 被阅读376次

    前后端分离:

    部署架构:

    setting.xml 文件的作用:
    settings.xml是maven的全局配置文件。而pom.xml文件是所在项目的局部配置。
    Settings.xml中包含类似本地仓储位置、修改远程仓储服务器、认证信息等配置。

    Repositories元素:
    远程仓库列表,它是maven用来填充构建系统本地仓库所使用的一组远程仓库。

    PS: .yml文件
    类似于properties文件
    在resource文件夹里

    日志:

    Mac快捷键 Command+O 搜索类
    日志框架:org.slf4j
    一、slf4J
    可以使用@slf4j注解直接使用

    log.debug()  //级别比info低
    //log使用变量
    log.info("name: {} , password: {}",name, password)
    

    二、Logback
    Logger作为日志的记录器,把它关联到应用的对应的context上后,主要用于存放日志对象,也可以定义日志类型、级别。
    Appender主要用于指定日志输出的目的地,目的地可以是控制台、文件、远程套接字服务器、 MySQL、PostreSQL、 Oracle和其他数据库等。
    Layout 负责把事件转换成字符串,格式化的日志信息的输出。

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->  
        <property name="LOG_HOME" value="c:/log" />  
        <!-- 控制台输出 -->   
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
           <!-- 日志输出编码 -->  
           <Encoding>UTF-8</Encoding>   
            <layout class="ch.qos.logback.classic.PatternLayout">   
                 <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> 
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n   
                </pattern>   
            </layout>   
        </appender>   
        <!-- 按照每天生成日志文件 -->   
        <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">   
            <Encoding>UTF-8</Encoding>   
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--日志文件输出的文件名-->
                <FileNamePattern>${LOG_HOME}/myApp.log.%d{yyyy-MM-dd}.log</FileNamePattern>   
                <MaxHistory>30</MaxHistory>
            </rollingPolicy>   
            <layout class="ch.qos.logback.classic.PatternLayout">  
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> 
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n   
                </pattern>   
           </layout> 
            <!--日志文件最大的大小-->
           <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
             <MaxFileSize>10MB</MaxFileSize>
           </triggeringPolicy>
        </appender> 
       <!-- show parameters for hibernate sql 专为 Hibernate 定制 -->  
        <logger name="org.hibernate.type.descriptor.sql.BasicBinder"  level="TRACE" />  
        <logger name="org.hibernate.type.descriptor.sql.BasicExtractor"  level="DEBUG" />  
        <logger name="org.hibernate.SQL" level="DEBUG" />  
        <logger name="org.hibernate.engine.QueryParameters" level="DEBUG" />  
        <logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" />  
        
        <!-- 日志输出级别 -->
        <root level="INFO">   
            <appender-ref ref="STDOUT" />   
            <appender-ref ref="FILE" />   
        </root> 
         
         <!--日志异步到数据库 -->  
        <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
            <!--日志异步到数据库 --> 
            <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
               <!--连接池 --> 
               <dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
                  <driverClass>com.mysql.jdbc.Driver</driverClass>
                  <url>jdbc:mysql://127.0.0.1:3306/databaseName</url>
                  <user>root</user>
                  <password>root</password>
                </dataSource>
            </connectionSource>
      </appender> -->
    </configuration>
    

    @DynamicUpdate
    @Data 包含了生成Getter()、Setter()、ToString()等方法

    Assert

    JAVA Collectors
    Collectors中提供了将流中的元素累积到汇聚结果的各种方式

    List<Menu> menus=Menu.getMenus.stream().collect(Collectors.toList())
    

    For - each 写法
    for each语句是java5新增,在遍历数组、集合的时候,for each拥有不错的性能。

    public static void main(String[] args) {
            String[] names = {"beibei", "jingjing"};
            for (String name : names) {
                System.out.println(name);
            }
        }
    

    for each虽然能遍历数组或者集合,但是只能用来遍历,无法在遍历的过程中对数组或者集合进行修改。

    BindingResult
    一个@Valid的参数后必须紧挨着一个BindingResult 参数,否则spring会在校验不通过时直接抛出异常

    @Data
    public class OrderForm {
    
        @NotEmpty(message = "姓名必填")
        private String name;
    }
    

    后台:

    @RequestMapping("save")  
        public String save( @Valid OrderForm order,BindingResult result) {  
            //  
            if(result.hasErrors()){  
                List<ObjectError> ls=result.getAllErrors();  
                for (int i = 0; i < ls.size(); i++) {  
                    log.error("参数不正确,OrderForm={}", order);
                    throw new SellException(
                     ………… ,
                 result.getFeildError.getDefaultMessage()
                  )
                    System.out.println("error:"+ls.get(i));  
                }  
            }  
            return "adduser";  
        }
    

    result.getFeildError.getDefaultMessage()可抛出“姓名必填” 的异常。

    4、List转为Map

    public class Apple {
        private Integer id;
        private String name;
        private BigDecimal money;
        private Integer num;
       /*构造函数*/
    }
    
    List<Apple> appleList = new ArrayList<>();//存放apple对象集合
    Apple apple1 =  new Apple(1,"苹果1",new BigDecimal("3.25"),10);
    Apple apple12 = new Apple(1,"苹果2",new BigDecimal("1.35"),20);
    Apple apple2 =  new Apple(2,"香蕉",new BigDecimal("2.89"),30);
    Apple apple3 =  new Apple(3,"荔枝",new BigDecimal("9.99"),40);
    appleList.add(apple1);
    appleList.add(apple12);
    appleList.add(apple2);
    appleList.add(apple3);
    
    Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1,k2)->k1));
    

    Collection的子类:List、Set
    List:ArrayList LinkedList Vector
    List:有序容器,允许null元素,允许重复元素
    ArrayList 最为流行,它提供了使用索引的随意访问。

    Set:HashSet、LinkedHashSet
    最流行的是基于 HashMap 实现的 HashSet。
    由hashCode()和equals()保证元素的唯一性。
    Set:无序容器,不允许重复对象

    Map、List、Set都是接口,不是类。

    GitHub

    分布式锁

    线程锁:当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效,因为线程锁的实现在根本上是依靠线程之间共享内存实现的。如synchronized

    进程锁:为了控制同一操作系统中多个进程访问某个共享资源。
    分布式锁:当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问。

    分布式锁的实现:

    @ControllerAdvice处理全局异常

    Mybatis注解方式的使用:
    @insert 用注解方式写SQL语句

    分布式系统的下的Session

    1、分布式系统:多节点,节点发送数据交互,不共享主内存,但通过网络发送消息合作

    分布式:不同功能模块的节点
    集群:相同功能的节点

    2、Session 与token
    服务端在HTTP头里设置SessionID而客户端将其保存在cookie
    而使用Token时需要手动在HTTP头里设置,服务器收到请求后取出cookie进行验证。

    都是一个用户一个标志

    3、分布式系统中的Session问题:

    高并发:通过设计保证系统能够同时并行处理很多请求

    高并发量的请求到达服务端的时候通过负载均衡的方式分发到集群中的某个服务器,这样就有可能导致同一个用户的多次请求被分发到集群的不同服务器上,就会出现取不到session数据的情况

    根据访问不同的URL,负载到不同的服务器上去
    三台机器,A1部署类目,A2部署商品,A3部署单服务

    通用方案:用Redis保存Session信息,服务器需要时都去找Redis要。登录时保存好key-value,登出时让他失效

    垂直扩展:IP哈希 IP的哈希值相同的访问同一台服务器

    session的一致性:只要用户不重启浏览器,每次http短连接请求,理论上服务端都能定位到session,保持会话。

    Redis作为分布式锁

    高并发:通过设计保证系统能够同时并行处理很多请求

    同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全

    线程的Block状态:
    a.调用join()和sleep()方法,sleep()时间结束或被打断
    b.wait(),使该线程处于等待池,直到notify()/notifyAll():不释放资源

    此外,在runnable状态的线程是处于被调度的线程,Thread类中的yield方法可以让一个running状态的线程转入runnable

    Q:为什么wait,notify和notifyAll必须与synchronized一起使用?
    Obj.wait()、Obj.notify必须在synchronized(Obj){…}语句块内。
    A:wait就是说线程在获取对象锁后,主动释放对象锁,同时本线程休眠。

    A:多线程并发的环境下,如何保证一个代码块只有一个线程能访问?
    Q:Synchronized ReentrantLock

    Q:Synchronized:
    A:Synchronized就是非公平锁,它无法保证等待的线程获取锁的顺序

    公平和非公平锁的队列都基于锁内部维护的一个双向链表,表结点Node的值就是每一个请求当前锁的线程。公平锁则在于每次都是依次从队首取值。

    ReentrantLock重入性:
    重入锁的重入性是基于Thread.currentThread()实现的: 如果当前线程已经获得了锁, 那该线程下的所有方法都可以获得这个锁
    ReentrantLock锁的释放是逐级释放的,也就是说在 可重入性 场景中,必须要等到场景内所有的加锁的方法都释放了锁, 当前线程持有的锁才会被释放。

    分布式锁:当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问。

    保证单线程地访问:

    setNX set if not exist
    如果key不存在,将key设置为value,存在的话就什么也不做

    用!setNX加锁

    在JAVA端为SetIfAbsent(),如果返回TRUE说明加锁成功
    GetAndSet保证每次只有一个线程拿到锁

    delete(key)

    GETSET 先GET再SET

    锁超时:
    如果一个线程在得到锁的过程中挂掉,这块资源会被永远锁住
    需要设置一个超时时间
    redis中可以使用expire命令设置一个键的生存时间,到时间后redis会自动删除它。

    解铃还需系铃人
    使用key来当锁,因为key是唯一的。
    value,我们传的是requestId/时间,具有唯一性
    首先获取锁对应的value值,检查是否与requestId相等,如果相等则删除锁(解锁)。

    cacheable 只会执行一次
    cacheput 每次会执行方法里的内容,把执行完的内容放到Redis里面去。

    对数据库加锁
    乐观锁 与 悲观锁的实现
    悲观锁依赖数据库实现:
    select * from account where name=”Erica” for update
    这条sql 语句锁定了account 表中所有符合检索条件(name=”Erica”)的记录。

    代码层加锁:

    String hql ="from TUser as user where user.name='Erica'";
    Query query = session.createQuery(hql);
    query.setLockMode("user",LockMode.UPGRADE); //加锁
    List userList = query.list();//执行查询,获取数据
    

    相关文章

      网友评论

      • 阿龙2017:源代码在那里下载呢?
        Tommmmm:@阿龙2017 我晚一点把git地址留一下

      本文标题:SpringBoot微信点餐系统

      本文链接:https://www.haomeiwen.com/subject/fisziftx.html