Spring是什么?干什么的?怎么用?
Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。
spring是一个万能的框架,方便解耦,开发,配置事务等等
Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。
Spring的核心机制是管理Bean
SpringMVC是什么?干什么的?怎么用?
SpringMVC是Spring框架的一个模块,使用Spring进行WEB开发时,可以使用Spring MVC框架。
web.xml中配置DisapatcherServlet,编写配置文件xxx-servlet.xml
mybatis是什么?干什么的?怎么用?
MyBatis 是一个持久层框架,用于 SQL查询、存储过程以及高级映射。两种使用方式:xml和注解。
Springboot是什么?干什么的/优点?
Spring Boot是用来简化Spring应用初始搭建以及开发过程的全新框架,自动配置spring,maven管理,无需部署,快速构建spring项目。
Spring secuity是什么?干什么的?
spring secuity是一个安全框架,用于授权和认证。
Redis 是一个开源的,高性能的 key-value 数据库。数据缓存在内存中,但是可以持久化到磁盘。
Redis能干什么?
Redis特性
HTML、css、JavaScript
ajax
AJAX 是一种可以局部刷新网页的技术。通过 HTTP 请求加载远程数据。即可发送异步的ajax请求等。(客户端进行ajax操作,服务器返回json数据)
ajax三要素:异步交互、XMLHttpRequest对象、回调函数。
Web service 是什么?如何使用?
基于 Web 的服务:服务器端整出一些资源让客户端应用访问。比如天气预报数据。
编写服务端和客户端,进行发布访问 WebService Client–>(访问) WebServiceServer
webservice的优缺点?
==优:==1.采用xml支持跨平台远程调用.;2、基于http的soap协议,可跨越防火墙;3.支持面向对象开发;4.有利于软件和数据的重用,实现松耦合。
==缺:==1、数据传输的效率不高;2、单机应用程序;3、局域网的同构应用程序。
实现webservice的框架?
目前开发Web Service的几个框架,分别为Axis,axis2,Xfire,CXF以及JWS。
客户端调用WebService的方式:
1.通过wximport生成代码
2.通过客户端编程方式
3.通过ajax调用方式
4.通过 URL Connection 方式调用
服务端使用cxf+spring和注解实现服务端发布
NIO API
什么是Java NIO,它的工作原理是什么?
NIO是非阻塞式I/O模式,采用了通道和缓冲区的形式来进行处理数据。
专门的线程来处理 IO 事件,并负责分发。 事件驱动机制为:事件到的时候触发,而不是同步的去监视事件。
OOP,面向对象程序设计,是一种计算机编程架构。核心思想:封装,继承,多态.
简单的说,类和对象是对一件事物的抽象,可以有自己的访问方式(如public),成员变量,成员函数,继承和被继承这样的关系。
而结构体,只是用来表示一个结构的,它有成员变量,成员函数(c++后来加入的……)。但是没有访问方式和继承这样的关系,它只是用于表示一种数据结构。
Linux login命令用于登入系统。
快速排序时间复杂度 O (nlogn),
快速排序精髓:
一、先从数列中取出一个数作为基准数
二、分区,将比这个数大的数全放到它的右边,小于或等于它的数全部放到它的左边
三、对左右区间重复步骤(二),直到各区间只有一个数为止
String不是基本的数据类型,是final修饰的java类,java中的基本类型一共有8个,它们分别为:
1 字符类型:byte,char
2 基本整型:short,int,long
3 浮点型:float,double
4 布尔类型:boolean
含有abstract修饰符的class即为抽象类,抽象类中的方法不必是抽象的。
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。
1.抽象类可以有构造方法、普通成员变量、静态方法,接口中不能有构造方法、普通成员变量、静态方法等等。
因为:abstract class类中定义抽象方法必须在具体(Concrete)子类中实现
相同点:都不能创建实例对象。
2.3,小数点的数如果没有后缀,默认的是double型的,float要加后缀f.
List和Map的区别
List:是存储单列数据的集合,存储的数据是有序并且是可以重复的。
Map:是存储双列数据的集合,通过键值对存储数据,存储 的数据是无序的,Key值不能重复,value值可以重复。
list、set、map的区别
1、简单易学、有丰富的类库
2、面向对象(Java最重要的特性,让程序耦合度更低,内聚性更高)
3、与平台无关性(JVM是Java跨平台使用的根本)
4、可靠安全
5、支持多线程
面向过程:面向过程性能比面向对象高。
面向对象:面向对象易维护,易复用,易扩展。
GET就是获取资源,POST就是创建资源,PUT就是更新资源,DELETE就是删除资源。
静态变量、静态方法、静态块、静态内部类、静态导包。
访问权限 类 包 子类 其他包
public ∨ ∨ ∨ ∨ (对任何人都是可用的)
protect ∨ ∨ ∨ × (继承的类可以访问以及和private一样的权限)
default ∨ ∨ × × (包访问权限,即在整个包内均可被访问)
private ∨ × × × (作用于当前类)
即:类的成员不写访问修饰符时默认为default。默认对于同一个包中的其他类相当于公开(public),对于不是同一个包中的其他类相当于私有(private)。
Java中,外部类的修饰符只能是public或默认,类的成员(包括内部类)的修饰符可以是以上四种。
4种:
Map:key-value key不可以重复,value可以重复
HashMap:无序,key不可以重复(hashCode和equals),key允许为空
TreeMap:按照key进行升序排序,key不可重复(与compareTo方法有关)
HashTable:与HashMap相近,区别在于HashTable中的方法基本都是同步方法,key不允许null,直接会抛出NullPointException
遍历map的方式:
public class Example02 {
public static void main(String[] args) {
Map map = new HashMap();
map.put("1", "老大");
map.put("2", "老二");
map.put("3", "老三");
Set keySet = map.keySet(); //获取键的集合
Iterator it = keySet.iterator(); //迭代键的集合
while(it.hasNext()) {
Object key = it.next();
Object value = map.get(key); //获取每个键所对应的值
System.out.println(key+" : "+value);
}
}
}
相同点:
实现原理相同,功能相同,底层都是哈希表结构,查询速度快,在很多情况下可以互用
不同点:
1、Hashtable是早期提供的接口,HashMap是新版JDK提供的接口。
2、Hashtable继承Dictionary类,HashMap实现Map接口。
3、Hashtable线程安全,HashMap线程非安全。
4、Hashtable key不允许null值,HashMap允许null值。
Hashtable: 线程安全、效率低。(内部有上锁的控制synchronized)
HashMap:线程不安全、效率高。(多个线程同时操作这一个HashMap,可能出现线程不安全的情况,甚至出现死锁)
ConcurrentHashMap:分段锁,将锁的力度变小,兼顾两者,保证线程安全和性能
(老版本升级,兼容新版本时)
hashCode相等,equals也不一定相等, 两个类也不一定相等
equals相同, 说明是同一个对象, 那么hashCode一定相同
ArrayList底层的实现是Array, 数组扩容实现,搜索和读取数据是很快。
LinkList是一个双链表,在添加和删除元素时性能高.但在get与set方面弱于ArrayList。
Vector 和ArrayList类似,但属于强同步类。但ArrayList是线程不安全的,Vector是线程安全的(Vector的关键方法都使用了synchronized修饰)。扩容时候ArrayList扩0.5倍,Vector扩1倍
区别:
执行速度不同:string最慢。
线程安全不同:String、StringBuffer是线程安全的,StringBuilder是线程不安全的
==本质区别:==String类是不可变类,值不可变的,StringBuffer、StringBuilder是可变类。
联系:StringBuffer、StringBuilder和String一样,也用来代表字符串。
String类的场景:在字符串不经常变化的场景中
StringBuffer类的场景:在频繁进行字符串运算,并且运行在多线程环境中。
StringBuilder类的场景:在频繁进行字符串运算,并且运行在单线程的环境中。
继承Thread类来创建线程:
a.首先创建一个任务类extends Thread类,因为Thread类实现了Runnable接口,所以自定义的任务类也实现了Runnable接口,重写run()方法,其中定义具体的任务代码或处理逻辑。
b.创建一个任务类对象,可以用Thread或者Runnable作为自定义的变量类型。
c.调用自定义对象的start()方法,启动一个线程。
示例代码:
//每个任务都是Runable接口的一个实例,任务是可运行对象,线程即可运行对象。必须创建任务类,重写run方法定义任务
public class EFT extends Thread {
private int a = 10;
@Override
//重写run方法,定义任务
public void run() {
while(a>=0)
{
System.out.println("$" + this.getName() + "(" + a + ")");
}
}
//调用start方法会启动一个线程,导致任务中的run方法被调用,run方法执行完毕则线程终止
public static void main(String[] args) {
EFT thread1 = new EFT();
EFT thread2 = new EFT();
thread1.start();
thread2.start();
System.out.println("火箭发射倒计时:");
}
}
java创建线程的三种方式:
继承Thread类创建线程类
通过Runable接口创建线程类
实现Callable接口
应用程序可以使用Executor [ɪɡˈzekjətə®] 框架来创建线程池
Runnable接口有如下好处:
①避免单继承的局限,一个类可以实现多个接口。
②适合于资源的共享
②同时线程池的效率也非常高,很容易实现和使用。
//继承Thread类
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(getName());
}
public static void main(String[] args) {
for(int i=0;i<10;i++){
new MyThread().start();
}
// 内部类 方式
new Thread(){
@Override
public void run() {
for (int x = 0; x < 10; x++) {
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}.start();
}
}
// 实现runnable接口
public class RunnableThreadTest implements Runnable {
@Override
public void run() {
System.out.println("run:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
System.out.println("main:"+ Thread.currentThread().getName());
RunnableThreadTest rt = new RunnableThreadTest();
new Thread(rt, "线程1").start();
// 用内部类的方式创建线程,实现runnable接口
new Thread(new Runnable() {
@Override
public void run() {
for (int x = 0; x < 10; x++) {
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}).start();
}
}
专业描述:当多个线程访问一个对象时,如果不用进行额外的同步控制或其他的协调操作,调用这个对象的行为都可以获得正确的结果,我们就说这个对象是线程安全的。
那么我们如何做到线程安全?
一般采用synchronized关键字给代码块或方法加锁
在开发中,如果需要拼接字符串,使用StringBuilder还是StringBuffer?
场景一:
如果是多个线程访问同一个资源,那么就需要上锁,才能保证数据的安全性。
这个时候如果使用的是非线程安全的对象,比如StringBuilder,那么就需要借助外力,给他加synchronized关键字。或者直接使用线程安全的对象StringBuffer。
场景二:
如果每个线程访问的是各自的资源,那么就不需要考虑线程安全的问题,所以这个时候,我们可以放心使用非线程安全的对象,比如StringBuilder。
在方法中,创建对象,来实现字符串的拼接使用哪个好?
建议创建StringBuilder,这时候相当是每个线程独立占有一个StringBuilder对象,不存在多线程共享一个资源的情况,所以我们可以安心使用,虽然StringBuilder本身不是线程安全的。
什么时候需要考虑线程安全?
1,多个线程访问同一个资源
2,资源是有状态的,比如我们上述讲的字符串拼接,这个时候数据是会有变化的
因为java有个重要的特性,叫垃圾自动回收机制,所以答案是多线程,这里面有两部分,主线程(用户线程),垃圾回收线程GC(守护线程)同时存在。
线程与进程相似,但线程是一个比进程更小的执行单位。线程也被称为轻量级进程。
程序是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码。
进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。
关系:系统运行一个程序即是一个进程从创建,运行到消亡的过程。一个进程在其执行的过程中可以产生多个线程。
初始状态、运行状态、阻塞状态、等待状态、超时等待状态、终止状态
new、runnable、blocked、waiting、time_waiting、terminated。
序列化:将 Java 对象转换成字节流的过程。
反序列化:将字节流转换成 Java 对象的过程。
当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理。
如何实现对象的序列化?
1、新建一个实体对象,实现Serializable接口,这个实体对象就可以进行序列化了
2、另一个类中序列化这个实体类,并且将序列化之后的字节序列存在磁盘上。
public class SerializableDemo {
public static void main(String[] args) throws Exception {
//序列化一个对象
ObjectOutputStream objOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\obj.txt"));
Person person = new Person();
person.setName("Tom");
person.setAge(24);
//写入字面值常量
objOutputStream.writeObject("将对象序列化");
//写入匿名对象
objOutputStream.writeObject(new Date());
//写入对象
objOutputStream.writeObject(person);
//反序列化一个对象
ObjectInputStream objInputStream = new ObjectInputStream(new FileInputStream("D:\\obj.txt"));
System.out.println("读取的字面值常量:"+(String)objInputStream.readObject());
System.out.println("读取的匿名对象"+(Date)objInputStream.readObject());
System.out.println("读取person对象"+((Person)objInputStream.readObject()).toString());
}
}
对于不想进行序列化的变量,使用 transient 关键字修饰。transient 只能修饰变量,不能修饰类和方法。
通过异常体系保证程序的健壮性。
error: 一般指jvm错误,
runtimeexception (运行时异常):LogicException 逻辑异常,代码写得不严谨,数组越界,空指针异常。
Java可抛出(Throwable)的结构分为三种类型:被检查的异常(CheckedException),运行时异常
(RuntimeException),错误(Error)。
执行,并且finally的执行早于try里面的return
结论:
1、不管有木有出现异常,finally块中代码都会执行;
Java 中 IO 流分为几种?
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
25、java反射的作用于原理
1、定义:
这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
2、哪里会用到反射机制?
jdbc、hibernate,struts等框架使用反射实现的
3、反射的实现方式:
获取Class对象
单例设计模式:即某个类在整个系统中只能有一个实例对象可被获取和使用的代码模式。
例如:代表JVM运行环境的Runtime类。
要点:
几种常见形式:
饿汉式:直接创建对象,不存在线程安全问题
* 1、构造器私有化
* 2、自行创建,并且用静态变量保存
* 3、向外提供这个实例
* 4、强调这是一个单例,我们可以用final修改
public class Singleton1 {
public static final Singleton1 INSTANCE =new Singleton1();
private Singleton1(){
}
}
* 枚举类型--最简洁:表示该类型的对象是有限的几个
* 我们限定为一个,就成了单例
public enum Singleton2 {
INSTANCE;
}
public class Singleton3 {
public static final Singleton3 INSTANCE;
static {
INSTANCE= new Singleton3();
}
private Singleton3(){
}
}
测试类:获取这个对象
public class TestSingleton1 {
public static void main(String[] args) {
Singleton1 s = Singleton1.INSTANCE;
System.out.println(s);
}
}
懒汉式:延迟创建这个实例对象。
线程不安全(适用于单线程)
* 1、构造器私有化
* 2、用一个静态变量保存这个唯一的实例
* 3、提供一个静态方法,获取这个实例对象
public class Singleton4 {
private static Singleton4 instance;
private Singleton4(){
}
public static Singleton4 getInstance(){
if(instance==null){
instance = new Singleton4();
}
return instance;
}
}
线程安全(适用于多线程)
小结:
单例、工厂模式:SpringIOC就是使用了工厂模式。代理模式:SpringAOP就是使用的动态代理。
技术的角度:
JSP本质就是一个Servlet
JSP的工作原理:JSP->翻译->Servlet(java)->编译->Class(最终跑的文件)
应用的角度:
JSP=HTML+Java
Servlet=Java+HTML
各取所长,JSP的特点在于实现视图,Servlet的特点在于实现控制逻辑
Servlet是单实例的。
生命周期的流程:
创建对象–>初始化–>service()–>doXXX()–>销毁
创建对象的时机:
1,默认是第一次访问该Servlet的时候创建
2,也可以通过配置web.xml,来改变创建时机,比如在容器启动的时候去创建,DispatcherServlet(SpringMVC前端控制器)就是一个例子
1
执行的次数
对象的创建只有一次,单例
初始化一次
销毁一次
关于线程安全
构成线程不安全三个因素:
1,多线程的环境(有多个客户端,同时访问Servlet)
2,多个线程共享资源,比如一个单例对象(Servlet是单例的)
3,这个单例对象是有状态的(比如在Servlet方法中采用全局变量,并且以该变量的运算结果作为下一步操作的判断依据)
Cookie实际上是一小段的文本信息,Session在服务端开辟一块内存来保存session标识。
存储的位置不同
Session:服务端
Cookie:客户端
存储的数据格式不同
Session:value为对象,Object类型
Cookie:value为字符串,如果我们存储一个对象,这个时候,就需要将对象转换为JSON
存储的数据大小
Session:受服务器内存控制
Cookie:一般来说,最大为4k
生命周期不同
Session:服务器端控制,默认是30分钟,注意,当用户关闭了浏览器,session并不会消失
Cookie:客户端控制,其实是客户端的一个文件,分两种情况
1,默认的是会话级的cookie,这种随着浏览器的关闭而消失,比如保存sessionId的cookie
2,非会话级cookie,可通过设置有效期来控制,比如这种“7天免登录”这种功能,
就需要设置有效期,setMaxAge
Session机制背后的原理是,服务器会自动生成会话级的cookie来保存session的标识。
xml:可扩展标记语言,是一种用于标记电子文件使其具有结构性的标记语言。
json:(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。
二者区别:
它们都是一种数据交换格式。
1,xml是重量级的,json是轻量级的。
2,xml在传输过程中比较占带宽,json占带宽少,易于压缩。
3,xml和json都用在项目交互下,xml多用于做配置文件,json用于数据交互。
4,json可用jackson,gson等方法解析,xml可用dom,sax,demo4j等方式解析。
关于json
一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但是一般会包含状态码、返回消息、数据这几部分内容。
{
"success": true,
"code": 20000,
"message": "成功",
"data": {
"items": [
{
"id": "1",
"name": "刘德华",
"intro": "毕业于师范大学数学系,热爱教育事业,执教数学思维6年有余"
}
]
}
}
王维鑫
转发:
发生在服务器内部的跳转,所以,对于客户端来说,至始至终就是一次请求,所以这期间,保存在request对象中的数据可以传递
重定向:
发生在客户端的跳转,所以,是多次请求,这个时候,如果需要在多次请求之间传递数据,就需要用session对象
面试官的问题:
在后台程序,想跳转到百度,应该用转发还是重定向?
答案:重定向,因为转发的范围限制在服务器内部
1,JavaEE将企业级软件架构分为三个层次:
Web层:负责与用户交互并对外提供服务接口
业务逻辑层:实现业务逻辑模块
数据存取层:将业务逻辑层处理的结果持久化,方便后续查询
3,每个层都有各自的框架
WEB层:SpringMVC,Struts2,Struts1
业务逻辑层:Spring
数据持久层:Hibernate,MyBatis,SpringDataJPA,SpringJDBC
MVC是对Web层做了进一步的划分,更加细化
Model(模型) - 模型代表一个存取数据的对象或 JAVA POJO。
View(视图) - 视图代表模型包含的数据的可视化,比如HTML,JSP,Thymeleaf,FreeMarker等等
Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开,目前的技术代表是Servlet,Controller。
SpringMVC分为两个控制器
DispatchServlet:前端控制器,由它来接收客户端的请求,再根据客户端请求的URL的特点,分发到对应的业务控制器,比如UserController。
记得多少回答多少即可。
内置对象名 类型
request (HttpServletRequest)
response (HttpServletResponse)
config (ServletConfig)
application (ServletContext)
session (HttpSession)
exception (Throwable)
page (Object(this))
out (JspWriter)
pageContext (PageContext)
page域: 只能在当前jsp页面使用 (当前页面)
request域: 只能在同一个请求中使用 (转发才有效,重定向无效)
session域: 只能在同一个会话(session对象)中使用 (私有的,多个请求和响应之间)
context域: 只能在同一个web应用中使用 (全局的)
并发:同一个CPU执行多个任务,按细分的时间片交替执行
并行:在多个CPU上同时处理多个任务
JQuery中常见的选择器
基础选择器
1、ID选择器 $(“#ID”)
2、类选择器 $(“.class”)
3、标签选择器 $(“HTML表签”) $(“p”)
4、组合选择器 $(“selector1,selector2,…selectorN”)
层级选择器
1、空格 $(“selector1 selector2”):直接包含+间接包含
2、> $(“selector1>selector2”) :直接包含
3、加号 $(“selector1+selector2”):相邻的一个元素
4、~ $(“selector1~selector2”):后续所有兄弟元素
JQuery中的DOM操作
addClass
removeClass
添加/移除/获取某些HTML中的属性
获取/设置某些HTML元素的value属性
增:
1.1【插入单行】
insert [into] <表名> (列名) values (列值)
例:insert into Strdents (姓名,性别,出生日期) values (‘开心朋朋’,‘男’,‘1980/6/15’)
删:
2.1【删除<满足条件的>行】
delete from <表名> [where <删除条件>]
例:delete from a where name=‘开心朋朋’(删除表a中列值为开心朋朋的行)
改:
update <表名> set <列名=更新值> [where <更新条件>]
例:update tongxunlu set 年龄=18 where 姓名=‘蓝色小名’
查:
4.1、精确(条件)查询
select <列名> from <表名> [where <查询条件表达试>] [order by <排序的列名>[asc或desc]]
查询所有:select * from 表名;
4.1.2【查询部分行列–条件查询】
例:select i,j,k from a where f=5
说明:查询表a中f=5的所有行,并显示i,j,k3列
4.1.3【在查询中使用AS更改列名】
例:select name as 姓名 from a where xingbie=‘男’
说明:查询a表中性别为男的所有行,显示name列,并将name列改名为(姓名)显示
4.1.4 模糊查询
例:select * from a where name like ‘赵%’
4.2.2【使用between在某个范围内进行查询】
例:select * from a where age between 18 and 20
4.2.3【使用in在列举值内进行查询】
例:select name from a where address in (‘北京’,‘上海’,‘唐山’)
4.3.1【使用group by进行分组查询】
例:select studentID ,AVG(score) from student group by studentID (score)指的是列名
4.3.2【使用having子句进行分组筛选】
例:select studentID ,AVG(score) from student group by studentID having count(score)>1
注:由于where只能在没有分组时使用,分组后只能使用having来限制条件。
4.4.1内联接(只列出两张表关联查询符合条件的记录**)
例:select a.name,b.chengji from a,b **where a.name=b.name或者
select a.name,b.chengji from a inner join b on a.name=b.name
4.4.2.1【左外联接查询】
例:select s.id sid, s.name sname,c.id cid, from strdent s left join score c on s.id=c.sid 以左表为主
右外连接改为right 以左表为主
(1)求出员工总人数。 SELECT COUNT(*) FROM emp; – SELECT count(rowid) FROM emp;
(2)求出公司每月要支付的工资总数。 SELECT COUNT(sal) FROM emp;
(3)求出最高月薪、最低月薪。 SELECT MAX(sal), MIN(sal) FROM emp;
(4)求出公司的平均月薪。 SELECT AVG(sal) FROM emp;
SQL1999标准中多表连接的语法:
SELECT [DISTINCT] *|[列名 别名,…]
FROM 主表名 [别名]
JOIN_TYPE 从表名 [别名] ON 连接条件
WHERE 查询条件1
GROUPBY 分组表达式
HAVING 组过滤条件
ORDERY BY 排序表达式;
(5)显示每个部门的员工数量。 SELECT COUNT(rowid) FROM emp GROUP BY deptno;
(6)显示每种职位的名及平均月薪。SELECT job,AVG(sal) FROM emp GROUP BY job;
(7)显示平均月薪大于2000的部门编号及平均月薪。SELECT deptno,AVG(sal) FROM emp GROUP BY deptno HAVING AVG(sal) > 2000;
(注:聚合函数不能出现在WHERE子句中。)
(8)显示不是总裁(PRESIDENT)的职位名以及该职位的员工月薪总和,还要满足同职位的员工的月薪总和大于4500。输出结果按月薪的总和降序排列。
1、职位不是总裁的职位名:SELECT job FROM emp WHERE job!=‘PRESIDENT’;
2、按职位分组,求出月薪总和:SELECT job,SUM(sal) FROM emp WHERE job!=‘PRESIDENT’ GROUP BY job;
3、分组后过滤月薪总和大于4500:SELECT job,SUM(sal) FROM emp WHERE job!=‘PRESIDENT’ GROUP BY job HAVING SUM(sal) > 4500;
4、结果按月薪的总计降序排列:SELECT job,SUM(sal) FROM emp WHERE job!=‘PRESIDENT’ GROUP BY job HAVING SUM(sal) > 4 4500 ORDER BY SUM(sal) DESC;
select job,sum(sal) from emp group by job having sum(sal) >4500 and job!=‘PRESIDENT’ order by sum(sal) desc;
(9)求出部门平均月薪的最高值。 SELECT MAX(AVG(sal)) FROM emp GROUP BY deptno;
(10)求出部门平均月薪最高的部门编号和平均月薪。
SELECT deptno,AVG(sal) FROM emp GROUP BY deptno HAVING avg(sal)=(SELECT MAX(AVG(sal)) FROM emp GROUP BY deptno);
(11)查询出月薪大于2000的员工姓名、月薪、受雇日期及其所在的部门名,输出结果按受雇日期排序。
SELECT ename,sal,hiredate,dname FROM emp INNER JOIN dept ON emp.deptno=dept.deptno WHERE emp.sal>2000 ORDER BY hiredate;
(12)查询出月薪比“SMITH”高的员工信息。 Select * from emp where sal>(select sal from emp where ename=‘SCOTT’)
(13)查询出月薪最高的员工姓名和月薪。 Select ename,sal from emp where sal=(select max(sal) from emp)
(inodb /i nou db/、myisam/misam/ 、memory 、merge、archive )
事务是访问数据库的一个操作序列,数据库应用系统通过事务集来完成对数据库的存取。
注:事务必须服从ISO/IEC所制定的ACID原则。ACID是原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)
原子性是基础,隔离性是手段,一致性 是约束条件,而持久性是我们的目的。
l READ UNCOMMITTED 读未提交,脏读、不可重复读、幻读有可能发生。
l READ COMMITTED 读已提交,可避免脏读的发生,但不可重复读、幻读有可能发生。
l REPEATABLE READ 可重复读,可避免脏读、不可重复读的发生,但幻读有可能发生。
l SERIALIZABLE 串行化,可避免脏读、不可重复读、幻读的发生,但性能会影响比较大。
特别说明:
幻读,是指在本地事务查询数据时只能看到3条,但是当执行更新时,却会更新4条,所以称为幻读
第一范式:列不可分
第二范式:要有主键
第三范式:不可存在传递依赖
JDBC对事务的操作是基于Connection来进行控制的,具体代码如下:
try {
//开启事务
connection.setAutoCommit(false);
//做业务操作
//doSomething();
//提交事务
connection.commit();
}catch(Exception e){
//回滚事务
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
但,注意,事务的边界我们是放在业务层进行控制,因为业务层通常包含多个dao层D的操作。
1,作用的位置不同
synchronized [ˈsɪŋkrənaɪzd] 可以给方法,代码块加锁
lock只能给代码块加锁
2,锁的获取和释放机制不同
**synchronized无需手动获取锁和释放锁,**发生异常会自动解锁,不会出现死锁。
lock需要自己加锁和释放锁,如lock()和unlock(),如果忘记使用unlock(),则会出现死锁,
所以,一般我们会在finally里面使用unlock().
synchronized修饰成员方法时,默认的锁对象,就是当前对象
synchronized修饰静态方法时,默认的锁对象,当前类的class对象,比如User.class
1、线程A和线程B相互持有对方需要的锁,从而发生阻塞,最终变为死锁。
2,如何防止死锁?(重点)
减少同步代码块嵌套操作
降低锁的使用粒度,不要几个功能共用一把锁
尽量采用tryLock(timeout)的方法,可以设置超时时间,这样超时之后,就可以主动退出,防止死锁(关键)
分别是普通索引、唯一索引、聚集索引、主键索引、全文索引几种。
使用索引的优点:
使用索引的缺点:
唯一索引:在创建唯一索引时要不能给具有相同的索引值。
主键索引:在我们给一个字段设置主键的时候,它就会自动创建主键索引,用来确保每一个值都是唯一的。
聚集索引:我们在表中添加数据的顺序,与我们创建的索引键值相同,而且一个表中只能有一个聚集索引。
普通索引:它的结构主要以B+树和哈希索引为主,主要是对数据表中的数据进行精确查找。
全文索引:它的作用是搜索数据表中的字段是不是包含我们搜索的关键字,就像搜索引擎中的模糊查询。
索引是对数据库表中一个或多个列的值进行排序的结构,建立索引有助于快速获取信息。
第一种方式:在执行CREATE TABLE时创建索引
第二种方式:使用ALTER TABLE命令去增加索引
第三种方式:使用CREATE INDEX命令创建
删除索引:根据索引名删除普通索引、唯一索引、全文索引: alter table 表名 drop KEY 索引名
关系型数据库和菲关系型数据库
关系型:mysql、oracle、sqlserver等
菲关系型:redis、memcache、mogodb、hadoop等
14、mysql数据库默认的最大连接数?
100,可设置。
1、查询语句中不要使用select *
2、尽量减少子查询,使用关联查询(left join,right join,inner join)替代
3、减少使用IN或者NOT IN ,使用exists[ɪɡˈzɪsts],not exists或者关联查询语句替代
4、or 的查询尽量用 union或者union all 代替(在确认没有重复数据或者不用剔除重复数据时,union
all会更好)
5、应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
6、应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫
描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null
值,然后这样查询: select id from t where num=0
反射是一种在程序运行时,动态获取当前类对象的所有属性和方法的能力,可以动态执行方法,给属性赋值等操作的能力。
在java中,Class类就是关键API,在我们的许多框架的背后实现上,都采用了反射的机制来实现动态效果。
IOC:“控制反转”。可以自动管理依赖的对象,重点是解耦!
AOP:面向切面编程。方便我们将一些非核心业务逻辑抽离,从而实现核心业务和非核心业务的解耦,即关注业务逻辑的开发。
其他:声明式事物的支持、方便程序测试、方便集成各种优秀框架、降低Java EE API的使用难度。
Spring AOP ,面向切面编程。原理:JDK动态代理
IOC,即控制反转,是一种设计思想,就是容器控制应用程序所需要外部资源的创建和管理,然后将其反转给应用程序
DI,即依赖注入,一种实现手段,在系统运行过程中,动态的向某个对象注入它所依赖的对象。
1,默认是singleton,即单例模式(常用)
2,prototype,每次从容器调用bean时都会创建一个新的对象,比如整合Struts2框架的时候,spring管理action对象则需要这么设置。
3,request,每次http请求都会创建一个对象
4,session,同一个session共享一个对象
5,global-session
大家可以回顾下线程不安全构成的三要素:
1,多线程环境
2,访问同一个资源
3,资源具有状态性
那么Spring的bean模式是单例,而且后端的程序,天然就处于一个多线程的工作环境。
那么是安全的吗?
关键看第3点,我们的bean基本是无状态的,所以从这个点来说,是安全的。
所谓无状态就是没有存储数据,即没有通过数据的状态来作为下一步操作的判断依据
Spring支持编程式事务管理以及声明式事务管理两种方式。
声明式事务属于无侵入式,不会影响业务逻辑的实现,只需要在配置文件中做相关的事务规则声明或者通过注解的方式,便可以将事务规则应用到业务逻辑中。
Spring倡导的非侵入式的编程方式即声明式事务。
Spring支持的事务传播特性
**propagation_required:[ˌperpei’ɡeɪʃ(ə)n] **
Spring默认的传播机制,能满足绝大部分业务需求,如果外层有事务,则当前事务加入到外层事务,一块提交,一块回滚。如果外层没有事务,新建一个事务执行。
回滚规则
在默认设置下,事务只在出现运行时异常(runtime exception)时回滚,而在出现受检查异常(checked exception)时不回滚(这一行为和EJB中的回滚行为是一致的)。
1,首先,将请求分给前端控制器DispatcherServlet
2,DispatcherServlet查询HandlerMapping(映射控制器),从而找到处理请求的Controller(处理器)
3,Controller执行业务逻辑处理后,返回一个ModelAndView(模型和视图)
4,DispatcherServlet查询一个或多个ViewResolver(视图解析器),找到ModelAndView对应的视图对象,视图对象负责渲染返回给客户端
快速记忆技巧:
核心控制器捕获请求、
查找Handler、
执行Handler、
选择ViewResolver、
通过ViewResolver渲染视图并返回。
SpringMVC容器管理,controller,Handlermapping,ViewResolver
Spring容器管理,service,datasource,mapper,dao
@RequestMapping:做请求的URL,跟我们controller或者方法的映射关系
@RequestParam:做请求参数的匹配,当请求参数名称跟我们方法的参数名不一致的时候,可以做匹配
@GetMapping: 请求方式为GET
@PostMapping:请求方式为POST
@PathVariable:获取URL中携带的参数值,处理RESTful风格的路径参数
@CookieValue:获取浏览器传递cookie值
@RequestBody:接收请求中的参数信息,一般来说,接收一个集合或数组,或者以post方式提交的数据
@ResponseBody: 改变返回逻辑视图的默认行为,返回具体的数据,比如json
@Controller:
0Spring定义的,作用就是标明这是一个controller类
@RestController:@Controller+@ResponseBody的组合
(1)工厂模式:SpringIOC就是使用了工厂模式
(2)单例模式:Bean默认为单例模式。
(3)代理模式:Spring的AOP功能用到了JDK的动态代理;
(4)模板模式:Spring中jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,就是用到了模板模式。
(5)观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用。
(6)适配器模式:Spring AOP的增强或通知使用到了适配器模式。
(7)策略模式:Spring中资源访问接口Resource的设计是一种典型的策略模式。
(8)装饰器模式:Spring 中配置 DataSource 的时候。
Spring AOP的底层都是通过代理来实现的
一种是基于JDK的动态代理(类实现接口,使用JDK动态代理完成AOP)
一种是基于Cglib的动态代理(没有实现接口,采用CGlib动态代理完成AOP)
spring Aop的理解
AOP 是一种编程思想,可以横切进去,在方法之前、之后进行操作,比如输出一些日志记录、添加、修改一些功能等。
advice 通知
前置通知、后置通知、环绕通知、抛出通知。
PintCut:切入点
可以配置拦截的方法
Advisor:单元
将切入点和通知整合起来
1,悲观锁是利用数据库本身的锁机制来实现,会锁记录。安全
2,乐观锁是一种不锁记录的实现方式,采用CAS模式,一般采用version字段来作为判断依据。
优点:
缺点:
一级缓存总结:
1,一级缓存模式是开启状态
2,一级缓存作用域在于SqlSession
3,如果中间有对数据的更新操作,则将清空一级缓存。
要使用二级缓存,需要经历两个步骤
1,开启二级缓存(默认处于开启状态)
2,在Mapper.xml中,配置二级缓存(也支持在接口配置)
在标签下面添加标签即可
二级缓存作用域在于SqlSessionFactory。MyBatis的二级缓存默认采用的是Map的实现。二级缓存优先于一级缓冲。
第一种是使用标签,逐一定义数据库列名和对象属性名之间的映射关系。
第二种是使用sql列的别名功能,将列的别名书写为对象属性名。
有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页。
分为逻辑分页和物理分页(正常人,一般使用)。
首先,在MyBatis内部定义了一个拦截器接口
所有的插件都要实现该接口,来,我们看看这个接口的定义
public interface Interceptor {
Object intercept(Invocation invocation) throws Throwable;
Object plugin(Object target);
void setProperties(Properties properties);
}
那么其中一个关键的方法就是intercept,从而实现拦截
分页插件的原理:就是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
所以原理还是基于拦截器。
MySQL使用limit分页(计算参数为 开始序号(startNum),要查的总条数 (totalNum))
select * from stu limit m, n; //m = (startPage-1)*pageSize,n = pageSize
Oracle使用rownum分页,三层嵌套查询(计算参数为 开始序号(startNum) , 结束序号 (endNum))
select * from (
select rownum rn,a.* from table_name a where rownum <= x
//结束行,x = startPage*pageSize
)
where rn >= y; //起始行,y = (startPage-1)*pageSize+1
1、#是将传入的值当做字符串的形式,eg:select id,name,age from student where id =#{id},当前端把id值1,传入到后台的时候,就相当于 select id,name,age from student where id =‘1’. #{} 占位符 采用#可以解决SQL注入的问题。
2 、== 是 将 传 入 的 数 据 直 接 显 示 生 成 s q l 语 句 = = , e g : s e l e c t i d , n a m e , a g e f r o m s t u d e n t w h e r e i d = 是将传入的数据直接显示生成sql语句==,eg:select id,name,age from student where id = 是将传入的数据直接显示生成sql语句==,eg:selectid,name,agefromstudentwhereid={id},当前端把id值1,传入到后台的时候,就相当于 select id,name,age from student where id = 1. ${} 拼接符
1,基本的CRUD标签,select|insert|updae|delete
2,
<resultMap>、<parameterMap>、<sql>、<include>、<selectKey>
3,动态SQL标签:trim | where | set | foreach | if | choose | when | otherwise | bind等,其中为sql片段标签,通过标签引入sql片段
启动类上面的注解是@SpringBootApplication,主要组合包含了以下3 个注解:
@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项。
@ComponentScan:Spring组件扫描。
SpringCloud是基于Springboot的、微服务系统架构的一站式解决方案。
SpringCloud是一系列主流框架的集合,以SpringBoot的方式对外提供服务。
区别:
联系:
Sprigboot为SprigCloud提供了代码实现环境,使用SprigBoot将其它组件有机融合到了SprigCloud的体系架构中了。
一般来讲,会把一些经常进行查询、不经常修改或者不是特别重要的数据(转账、出账数据,财务系统)放到redis中作为缓冲
Memcache只能将数据缓存到内存中,无法自动定期写入硬盘,而Redis不同的是它会周期性的把更新的数据写入磁盘或者把修
改操作写入追加的记录文件,实现数据的持久化。
使用springboot整合,基于springboot的缓冲注解做到的。注解有:@Cacheable 一般用在查询方法上、@CachePut 一般用在新增方法上、@CacheEvict 一般用在更新或者删除方法上
具体:
存的是返回结果,list集合(url地址)
keys * get (key) exit 退出
key–value
原因:
如何回收:
意义:
首先,需要经过DNS(域名解析服务)将URL转换为对应的ip地址,实际上域名只是方便我们记忆,在网络上的每台主机交互的地址都是IP。
其次,我们需要通过这个ip地址跟服务器建立TCP网络连接,随后向我们的服务器发出http请求。注意,http协议是tcp的上层协议
最后,服务器接收到我们的请求,处理完毕之后,将响应数据放入到http的响应信息中,然后返回给客户端。
客户端浏览器完成对服务器响应信息的渲染,将信息展现在用户面前。
示意图:
传输层协议:TCP协议、UDP协议
应用层协议:FTP、HTTP、SMTP
网络层协议:IP协议
1xx | 客户端提出请求,等待服务器处理 |
---|---|
2xx | 成功 |
3xx | 重定向(登录完之后,直接跳到指定界面) |
4xx | 客户端错 |
5xx | 服务端错 |
首先,两者都是传输层的协议。
其次,
tcp提供可靠的传输协议,传输前需要建立连接,面向字节流,传输慢
udp无法保证传输的可靠性,无需创建连接,以报文的方式传输,效率高
经过3次握手,4次挥手。
3次挥手
可用天眼查企业相关信息。
a、实力!实力!实力! 关注高频问题
b、主动权思维。
c、着重查看应聘岗位所需的技术,了解产品、业务范围。
面试过程中相关:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nym8L9kv-1616060170688)(java基础笔试题总结.assets/image-20201011095522911.png)]
面试后:
罗列面试中遇到的问题,重新组织好答案,变成自己的语言。 脱稿
日志级别类别、日志输出位置、日志格式、日志输出形式、日志文件保留天数等。
log4j主要有三个重要的组件:
# 设置日志级别
logging.level.root=WARN
Log4j支持两种配置文件格式:
一个不错的参考配置
#############
# 输出到控制台
#############
# log4j.rootLogger日志输出类别和级别:只输出不低于该级别的日志信息DEBUG < INFO < WARN < ERROR < FATAL
# WARN:日志级别 CONSOLE:输出位置自己定义的一个名字 logfile:输出位置自己定义的一个名字
log4j.rootLogger=WARN,CONSOLE,logfile
# 配置CONSOLE输出到控制台
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
# 配置CONSOLE设置为自定义布局模式
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
# 配置CONSOLE日志的输出格式 [frame] 2019-08-22 22:52:12,000 %r耗费毫秒数 %p日志的优先级 %t线程名 %C所属类名通常为全类名 %L代码中的行号 %x线程相关联的NDC %m日志 %n换行
log4j.appender.CONSOLE.layout.ConversionPattern=[frame] %d{yyyy-MM-dd HH:mm:ss,SSS} - %-4r %-5p [%t] %C:%L %x - %m%n
################
# 输出到日志文件中
################
# 配置logfile输出到文件中 文件大小到达指定尺寸的时候产生新的日志文件
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
# 保存编码格式
log4j.appender.logfile.Encoding=UTF-8
# 输出文件位置此为项目根目录下的logs文件夹中
log4j.appender.logfile.File=logs/root.log
# 后缀可以是KB,MB,GB达到该大小后创建新的日志文件
log4j.appender.logfile.MaxFileSize=10MB
# 设置滚定文件的最大值3 指可以产生root.log.1、root.log.2、root.log.3和root.log四个日志文件
log4j.appender.logfile.MaxBackupIndex=3
# 配置logfile为自定义布局模式
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n
##########################
# 对不同的类输出不同的日志文件
##########################
# club.bagedate包下的日志单独输出
log4j.logger.club.bagedate=DEBUG,bagedate
# 设置为false该日志信息就不会加入到rootLogger中了
log4j.additivity.club.bagedate=false
# 下面就和上面配置一样了
log4j.appender.bagedate=org.apache.log4j.RollingFileAppender
log4j.appender.bagedate.Encoding=UTF-8
log4j.appender.bagedate.File=logs/bagedate.log
log4j.appender.bagedate.MaxFileSize=10MB
log4j.appender.bagedate.MaxBackupIndex=3
log4j.appender.bagedate.layout=org.apache.log4j.PatternLayout
log4j.appender.bagedate.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n
Logback和log4j非常相似,如果你对log4j很熟悉,那对logback很快就会得心应手。
乐学网-在线教育是一个基于springboot工程的多模块项目,分为前台用户系统和后台运营平台。项目采用前后端分离技术开发,前端部分,使用主流的前端框架Vue,基于Es6的开发规范,采用模块化的开发模式。后端部分,使用的是SpringBoot+SpringCloud进行微服务架构开发。
一、我参与了讲师、课程分类模块、服务预约模块、banner模块的动态展示。
在讲师、课程管理模块的开发接口整合了mybatisplus,用到了代码生成器策略,(增删改查配置相关mp插件,)并整合swagger进行接口测试(生成在线接口文档,方便接口测试),模块开发进行统一的返回结果,统一异常,统一日志处理。
(MyBatis-Plus是一个 MyBatis 的增强工具,封装许多方法、也有强大的特性,内置Mapper、条件构造器 Wrapper、支持主键自动生成、内置代码生成器、内置分页插件等等:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询)
首页显示的banner数据(轮播图),使用到了redis缓冲。(缓冲了轮播图的相关数据)使用mp实现crud操作。
在一个网站中首页面的访问量最大,对首页数据做了缓冲处理,可以提高查询效率
(redis使用的是redisTemplate模板并结合springdataredis,调用redis接口方法)
预约模块,在前台可以预约名师,后台接受数据,讲师可进行是否同意匹配以及查看匹配记录,之后回传数据到前端,学生查看预约结果。前端是vue+element-u6i组件实现,后端是相似的开发接口。
对于用户登录使用了spring security安全框架进行授权和认证,参考官方文档在SecurityConfig类中进行配置,可额外增加权限控制及注销,需结合thymeleaf。可定制登录页,以Cookie作为凭证媒介可实现rememberMe功能 。
用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程(可以从内存和数据库(正常)进行读取认证)。
auth.inMemoryAuthentication()。
用户授权指的是验证某个用户是否有权限执行某个操作。
在用户认证方面,Spring Security 框架支持主流的认证方式,包括 HTTP 基本认证、HTTP 表单验证、HTTP 摘要认证等。
在用户授权方面,Spring Security 提供了基于角色的访问控制和访问控制列表。
(编写http.authorizeRequests()请求,配置角色和请求路径)
在结合使用security和thymleaf,做注销功能时页面报404错误,因为做登录登出时使用的是get请求,不安全的,springboot默认开启防网站攻击csrf,需关闭。
在讲师管理模块做文件上传使用到了阿里云oss存储服务。
如何实现?
传统的文件上传是存储到Tomcat中或者储存到本地路径中。弊端:别人的电脑就无法访问到我硬盘中的文件了。
于是采用了阿里云oss存储,在线联网可以使所有人都访问,(众所周知,阿里云技术在国内是顶级的,在实际项目开发中很多人也都会用到阿里云oss存储,因为他是很好的云存储解决方案。)
没有达到一定的存储量,它是免费。即使收费也是比较优惠的。
具体如何使用:
1、开通“对象存储OSS”服务(需要注册阿里云账号、实名认证)
2、在管理控制台中创建Bucket(相当于包或文件夹)
3、通过java代码操作实现上传文件到阿里云oss(官方api文档有详细的使用说明)
在添加课程分类功能中,(是先把信息添加到execl表格中,)使用到了一个技术叫EasyExcel,用它来读取execl内容,然后添加到数据库中。
相对传统的表单数据添加使用EasyExcel可以实现分类信息的批量添加,减轻录入工作量,便于统计信息的归档。EasyExcel是阿里巴巴提供的一个针对excel简单、高效的开源处理框架,实现读和写操作。
具体如何使用:
编写具体的后台开发接口代码—>(获取上传过来的文件,读取文件内容,添加到数据库)其中实体类要和execl数据对应,读取关键点创建监听器。
课程分类列表使用树形结构显示等等
在服务注册、调用、熔断器、网关、配置中心如何操作?
二、Alice电子商城是一个基于SSM轻量级java开发框架搭建的平台,我参与了商品展示模块,注册登录模块,评论留言模块等。代码采用的分层方式,并进行了统一异常处理,配置了拦截器等。
商品展示模块中,有商品分类、排序、搜索、分页显示利用了PageHelper插件,
(在SqlSessionFactoryBean中配置PageHelper的分页插件,业务层设置分页所必须的参数,在Controller层将分页展示的数据传入PageHelper所提供的分页对象中,由于分页对象存储到request域中,视图层通过el表达式即可完成分页。)
注册使用了邮件验证激活账号(首先在数据库添加激活码和验证状态两个字段,注册时使用javamail发送邮箱验证链接,点击验证);
登录配置了拦截器。
订单结算通过更改商品状态。
乐学网-在线教育
1.影响比较深的一个问题是:跨域请求,在线教育项目是基于前后分离的一个项目,前后端采用不同端口访问,比如说9528端口访问8001端口,出现服务器错误,通过思考查询相关资料后,得到两种解决方式
2.多路由跳转同一页面问题,讲师的添加和修改的表单提及放在同一页面,修改再进行添加,数据没有清空(eduTeacher.clear())原因是:created()方法只会执行一次。:使用vue的监听机制实现表单清空
当然还有细节问题,在controller层参数的传递,接受,返回的数据格式问题
逻辑删除问题,使用乐观锁,根据乐观锁的版本号状态值的变化等
Alice电子商城
没有太多复杂的问题,最常遇见状态500问题,没有加载上下文路径。
权限访问控制问题,使用过滤器只能拦截相关页面,不能拦截请求路径,配置拦截器可以完成对全部的请求路径完成拦截。
一些具体问题记得不太清,但是在实际使用中遇到这类问题能够解决。
乐学网-在线教育
讲师、课程管理模块的开发接口整合了mybatisplus,用到代码生成器策略,(增删改查配置相关mp插件,)并整合swagger进行接口测试(生成在线接口文档,方便接口测试),模块开发进行统一的返回结果,统一异常,统一日志处理。 |
---|
首页显示的banner数据(轮播图),使用到了redis缓冲。使用mp实现crud操作。 |
对于用户登录使用了spring security安全框架进行授权和认证, |
在做文件上传使用到了阿里云oss存储服务,比如讲师头像上传 |
在添加课程分类功能中,(是先把信息添加到execl表格中,)使用到了一个技术叫EasyExcel,用它来读取execl内容,然后添加到数据库中。 |
课程分类列表使用树形结构显示 |
概念图:
ajax操作/异步请求操作(前端定义接口地址和参数、请求方式等)
前端得到数据用vue指令进行遍历显示。
什么是node.js?简单的说 Node.js 就是运行在服务端的 JavaScript,是 JavaScript的运行环境。
什么是NPM?Node.js的包管理工具,相当于后端的Maven
Es6:是一套标准,一套规范。
Nginx相关概念:
动静分离:不同服务器放置不同的资源,比如java代码放在tomcat中,一些静态资源(html、图片等)放在静态服务器中。然后根据不同的请求访问不同的服务器。
具体实现步骤?