on-java-8 知识总结(高频部分)

本文探讨了面向对象编程的关键概念,包括对象的状态、行为和身份,以及封装、代码复用、多态和继承。文章比较了Java和C++在处理对象控制权上的差异,强调了Java异常处理的优势。此外,还深入讨论了集合如数组和集合、迭代器以及不同类型的集合操作。文章还涉及了类的加载、静态和非静态成员的初始化,以及Java中的垃圾回收机制。

有的内容是高频内容(比如重载、多态),有的内容虽然也很有用但问不到(比如函数式编程、流)。本文已按频率顺序进行调整。

什么是对象

对象有状态、行为、身份。

  • 对象有内部数据(对应状态),
  • 方法(对应行为),
  • 独有的内存地址(对应身份)
    (当然,也要考虑有多台机器,或者持久化到硬盘上的情况)
    对象可以接受request,并做出反应。struct是死的,而对象具有应激性,对象是活的,对象是服务提供者,对象协助我们解决问题。
    如果把对象当成服务提供者,更容易写出高内聚的代码,因为想塞很多东西进一个类的时候你会意识到,这对一个服务提供者来说是不是太多了。此外,这种视角也有利于复用,当需要某种服务的时候,调用相应的服务提供者即可。

对象带来的好处

作为新的数据类型,能更好满足具体需求;
作为服务提供者,抽象程度更高。

封装的好处

避免外部意外修改private成员,减少bug。与const的好处类似。可以让系统的运作符合类设计者的想法,而不至于在实际使用中脱轨。“正确使用”。
使用者不需要掌握太多知识就能使用,“易用”。
开发者能在不影响使用者使用的情况下对接口的实现进行更新。“无感更新”。

代码复用

复用有两种基本方法,聚合和继承。委任不被java直接支持,但IDE一般会帮忙。

委任

委任是聚合与继承的折中。书中的例子是SpaceShip和SpaceShipControls的关系。
控制器应该是SpaceShip的一部分(聚合),同时SpaceShip应当具有SpaceShipControls的接口(类似继承)。

如何选择

不满足is a的时候,就不适合用继承。不应该滥用继承,用之前想一下聚合是否更加合适。

继承动作说明

子类继承父类的成员和方法,
子类和父类应当满足is a的关系(这也体现了里氏代换原则)。
继承之后,一般会添加新方法,或是覆写旧方法。子类是父类的超集。
一个类不仅是它自己,它还是它父类。

创建一个派生类的对象时,如果父类有无参构造函数,则这个无参构造函数会自动且先调用。
如果父类没有无参构造函数,或者你希望调用一个父类的有参构造函数,你需要显式super(参数)。
显式调用时,记得放在一开始,否则会报错。

多态示例

void doSomething(Shape shape) {
shape.erase();
// ...
shape.draw();
}
Circle circle = new Circle();
Triangle triangle = new Triangle();
Line line = new Line();
doSomething(circle);
doSomething(triangle);
doSomething(line);

由于向上造型,所以不会报错;
同样是doSomething,因为实际执行时类的不同而呈现不同的行为。

单根Hierarchy

java中所有类都是Object的子类,而C++中不存在这样一个单根。
C++这样做是为了兼容C,无单根更加自由。
单根结构更容易实现垃圾回收机制。
下面这段没看明白,说的也是单根结构的好处:
And since information about the type of an object is guaranteed to be in all objects, you’ll never end up with an object whose type you cannot determine. This is especially important with system-level
operations, such as exception handling (a language mechanism for reporting errors), and to allow greater flexibility in programming.

array和collections

用于各种对象数量甚至类型不确定的情况。
Collection是一个类(也有一个Collections类,collections.addAll可以输入变长参数),是众多容器的父类,有add/addAll方法(后者将一个collection内所有元素并入)、可以用for-in或迭代器遍历。
各种collection可以通过toArray转换为array。

array和collections是并列关系。
array是定长数组,调用add/delete等影响size的方法会RE。
An array associates numerical indexes to objects. It holds objects of a known type so you don’t have to cast the result when you’re looking up an object. It can be multidimensional, and it can hold primitives. Although you can create arrays at run-time, the size of an array cannot be changed once you create it.

arraylist是java中的vector,linkedlist是java中的链表。LinkedList adds methods to use it as a stack, a Queue or a double-ended queue (deque).

<E>表示泛型,可以解决collections的类型安全问题。泛型的泛,我认为指的是此处的E可以任意。
<?>跟不加没有区别,但这是一种对编译器的宣告,“我了解泛型和类型安全,但在这里我就是要所有类型”。
另外的写法是,<? super boundName>和<? extends boundName>。

下面代码中等式左边用了List,这是为了日后如果想改变,只用改这一行的右边。不过在使用右侧具体类的方法时,如果不是list中有的方法,会报错。

List<Apple> apples = new LinkedList<>();

下面的代码中,第二行显式声明了参数类型。

List<Snow> snow1 = Arrays.asList(new Crusty(), new Slush(), new Powder());
List<Snow> snow4 = Arrays.<Snow>asList(new Light(), new Heavy(), new Slush());

set的实现类包括HashSet、TreeSet、LinkedHashSet(保留插入顺序)。map类似。

list的remove、indexof、contains都依赖于其equals方法。retainAll和removeAll是集合运算中的交和减。set可以修改指定位置的值。list的addAll可以中插。

list、map会自动resize。

作者建议不要在新代码中使用stack,vector和hashtable。
作者主张使用arrayDeque而不要使用stack。原因是java1.0的stack实现很差,但一直因兼容而未废弃。
下面的代码利用泛型,完全使用arrayDeque实现了stack。从中也可见arrayDeque是跟stack很相似的。

import java.util.Deque;
import java.util.ArrayDeque;
public class Stack<T> {
	private Deque<T> storage = new ArrayDeque<>();
	public void push(T v) { storage.push(v); }
	public T peek() { return storage.peek(); }
	public T pop() { return storage.pop(); }
	public boolean isEmpty() { return storage.isEmpty(); }
	@Override
	public String toString() { return storage.toString(); }
}

set最常用于查找,所以一般用hashset,这样查找最快。

collections中不能放基本类型。不过可以寄希望于自动装箱。

队列除了模拟真实的排队,主要用途之一是多进程编程的进程通信。

P844有一个非常全面的println,每个容器类实现了哪些接口。

peek/element, poll/remove

Both peek() and element() return the head of the queue without removing it, but peek() returns null if the queue is empty and element() throws NoSuchElementException. Both poll() and remove()
remove and return the head of the queue, but poll() returns null if the queue is empty, while remove() throws NoSuchElementException.

iterator

iterator主要解决这样的场景:一开始用list实现,但后来想用set实现。
iterator不关心到底是哪一个collection,它只关心collection里面是什么类型。我认为这比C++中的iterator有更好的扩展性(C++中需要指定命名空间,相当于需要指定collection类型)。
Java中的iterator只能单向移动。ListIterator继承自Iterator,可以向前遍历。
只有四个动作,一是iterator(向collection请求一个iterator),二是next(调用后,it指向下一个,然后返回所指内容),三是hasNext,四是remove。

iterator遍历:

Iterator<Pet> it = pets.iterator();
while(it.hasNext()) {
	Pet p = it.next();
	System.out.print(p.id() + ":" + p + " ");
}

看样子,刚获得的iterator会指向一个head,而不是第一个数据。
iterator删除:

it = pets.iterator();
for(int i = 0; i < 6; i++) {
	it.next();
	it.remove();
}

看样子,Java的iterator remove不会造成迭代器失效的问题。其remove都是隐藏的效果。

Producing an Iterator is the least-coupled way of connecting a
sequence to a method that consumes that sequence, and puts far fewer
constraints on the sequence class than does implementing
Collection.
在实现自己的容器时,作者建议实现iterator,而不是实现collection。

只要实现了iterable,就能使用for-in遍历

c++和java在程序员控制权上的取舍

运行前就确定存储位置和生命周期,肯定比运行时才确定要更快。
C++把更多的决定权(比如对象destroy时机)交给了程序员。
而java中,所有的对象都存储在堆上。除了基本类型,一概使用动态内存分配。
java gc只负责释放内存,而这不是清理一个对象的全部。

java异常处理的优势

此处的对比对象是c式的返回值为-1、错误标志位设置等异常处理方法。

  • 被抛出的异常不会被忽略
  • 由于执行路径不同,java异常处理不会干扰工作代码(从可读性和易写性为程序员考虑)
  • 有恢复执行的机会,而不是单纯exit

对象与引用

java中的标识符(变量名)都是引用,就好像一个电视遥控器,而内存中的对象就像电视。
引用,也就是遥控器,存储在栈上;而对象本身,也就是电视,存储在堆里。

变量类型和存储位置

https://www.cnblogs.com/protected/p/6419217.html java中字符串的存储
①寄存器
②堆
③栈
④常量存储
Constant values are often placed directly in the program code, which is safe since they can never change. Sometimes constants are cordoned off by themselves so they can be optionally placed in read-only memory (ROM), in embedded systems.
⑤non-ram存储
serialized object 用于存储传输
persistent object 程序结束后仍能维持状态

需要注意的是,基本类型不是对象,直接存在栈上。
java中各基本类型的大小不随机器变化(所以Java中没有sizeof,所以没有必要),而且没有unsigned类型。

BigInteger和BigDecimal类没有对应的基本类型。后者是定点小数。

java中char是2个字节。

初始化

java中的数组不会出现未初始化和越界访问。如果是对象数组,自动初始化为null。如果是基本类型数组,内存被置0。
至于对象内的成员,如果是基本类型,会有自己的初始值(一般为0,boolean为false),对象内的对象默认为null。
对于C++,则取决于对象的存储位置,栈和堆上的对象内的基本类型是不会自动初始化的。
使用未初始化的局部变量时,java会报错。而C++可能只是发出警告。

可以通过调用new或者接收函数(不能使用尚未初始化的成员作为入参)返回值来初始化对象的成员。
所有成员的初始化都在构造函数执行之前。

静态成员的初始化只在必要时进行(如果该类没有对象或者用户没有用类名进行访问,那就不会创建);
静态成员的初始化早于非静态成员的初始化;
静态成员只会初始化一次(不管有多少个对象)。
可以使用static代码块来对static成员进行初始化。类似,可以用不带static的代码块来对非static成员进行初始化(有匿名内部类时不得不这么写。)

java的命名空间

c++中试图用namespace解决命名冲突,java中则采用倒转的域名来做包名,从而解决命名冲突。
目前包名统一为小写字母。
由于域名的每个dot表示子目录,这种方式会形成较深的目录结构和大量空目录。好在ide可以代劳。
java会在CLASSPATH下根据文件开头的package信息(比如com.demo)来找。

java不需要函数声明

在java中,不需要函数声明。只要后面有函数定义,前面就能使用这个函数。

静态变量和方法的访问

类中的静态变量和方法,可以通过类名访问,也可以通过对象名访问。

构造函数

构造函数的名字和类名完全相同。所以构造函数的首字母是大写的,而其它方法的首字母是小写的。
在C++中,无参构造函数称为默认构造函数。
如果没写构造函数,编译器会帮你安排一个默认无参构造函数。如果写了,就不会安排。
可以在构造函数中调用其它构造函数,以减少重复代码。

.java,.class,.jar

一个.java文件称为一个编译单元,其中应当有一个跟文件同名的类,且其中只有一个public类。
言外之意是一个.java文件中可以有多个类。由于一个.class文件对应一个类,所以编译生成的.class文件会比.java文件多。所有的.class文件会被打包成jar文件。

比较变量是否相等

==和!=比较的是两个reference的值。对于小整数Integer,结果为true。对于大整数则不然。大小的界限似乎是-127-128。原因是缓存。书中没提,亲测如此。
使用equals判断对象内容是否相同的时候,记得要先定义class的equals方法,默认的equals是判断reference是否相同

方法签名与重载

方法名称和参数列表共同组成方法的签名。
重载只需要保证参数类型列表不同即可,即使只是交换顺序也行。
书中讨论了基本类型做参数重载时的宽度和转型问题(比如同名函数的int和long版本),此处不详述。
重载不考虑返回值,因为如果参数列表相同而仅返回值不同,是无法确认是哪个函数的。函数签名也是不考虑返回值的。

gc机制

gc只知道如何回收new出来的内存,如果不是new出来的(唯一的例子是,native method,也就是调用了C/C++代码的时候),需要在gc之前调用finalize,finalize需要自己实现。
finalize其实也有其它作用,比如做一些检查。书中的例子是,在finalize中检查book是否check in(业务需求是,不应该回收没有check in的book)。
finalize与C++的析构函数不同。在C++中,每一个对象都一定会被destroy。在Java中,不是所有的对象都会被回收(只有JVM认为空间不太够的时候,才会开始回收和finalize,这样可以减少不必要的开销)。实际上回收不是destroy。回收只管存储。而destroy的范围更广。
finalize不应被显式直接调用。
Joshua Bloch goes further in his section titled “avoid finalizers”:“Finalizers are unpredictable, often dangerous, and generally unnecessary.” ,Effective Java Programming Language Guide
通过System.gc可以强制调用gc。

gc机制可以加快内存分配,这使得Java中创建object比C++程序员想象中要更快。
书中的比方是,C++的堆内存分配就像庭院划分草皮,而Java的堆内存分配就像传送带。Java中有类似heap pointer的东西,就好像栈顶指针一样。

@override

首先,这是注释。为什么要有这个注释,给谁看?
这句注释告诉编译器你的目的,函数名称没有写错,我知道我是要重写一个已经有了的函数。注意,试图override的时候,signature必须完全一样,否则会出现父子一起重载的怪像。如果加了@override,那么在你搞错signature的时候,编译器会提醒你,你是在重载而不是在覆写。
此外,也可以提示其它程序员。

成员与方法的可见性

protected成员子类可以访问。如果不声明可见性,默认使用package access(或称为friendly),也就是同一个package下的视为public,不同package下的视为private。
如果若干java文件位于同一目录下,且它们都没有显式指定package,那么它们被认为同属于一个default package。因为默认包的类没有包名, 在被有包结构的类引用时,会被当成本包内的类,就会无法识别。应该养成建立包结构的习惯。
在这里插入图片描述
子类中继承的成员不能拥有比原先赋值的权限更低的访问权限,只能拥有更高的访问权限。private成员是无法继承的。
一种编程习惯是public在最前,private在最后,这样读者就可以轻松避开内部实现。

一般建议不要有protected类型的field,实现同样的功能最好用private的field配合protected的set方法。

类的可见性

类要么是public,要么是package access(仅内部类可以为private或protected)。
如果类是private的,那么没有任何其它类能访问它。要想实现类似的效果(除了我,谁都不能造,想造只能通过我),有两个方法,都需要将其构造器显式声明为private:
要用时请我做一个:在该类内提供一个static方法,在static方法中调用自己的构造函数并返回给请求者。
做好一个,要用时找我借:在该类内提供一个new好的static的该类实例,需要时返回请求者。
第二种方法是单例模式的实现。

如果构造方法是private的,那么这个类无法被继承。

关于main函数

同一个java文件中可以有多个类,每个类中都可以有main函数。
只要通过java 类名即可指定该类下的main函数。类的main函数可以用于类的测试,不必删除。如果不希望发布的产品中出现测试代码,也可以采用下面的方法,这样Tester会单独生成一个class文件,发布时不要这个class文件即可。

public class TestBed {
	public void f() { System.out.println("f()"); }
	public static class Tester {
		public static void main(String[] args) {
			TestBed t = new TestBed();
			t.f();
		}
	}
}

即使类是package access的,其main函数是public的。

final关键字

final关键字在不同的语境下有不同的含义。一般是“不可变”的意思。

final修饰数据

final用于修饰data时,可以表示常数。在编译期间即可确认,并可提前计算,以减少运行耗时。注意,如果使用final来声明data,需要提供值(要么当行提供,要么在构造函数中提供)。
final用于修饰一个reference时,reference本身不变,但不保证reference指向的对象不被修改。Java语言本身不支持一个“不变”对象(不过可以自己实现)。

final修饰参数

如果一个输入参数是final的,那么这个函数不能修改这个参数。

final修饰方法

确保子类继承后不能再重写这个方法。出于设计目的,希望一个方法的内容不被修改。
在早期,final方法会得到inline优化。不过据说现在不这么干了,作者认为改善甚微。
private方法是不会被重写的(You haven’t overridden the method, you’ve just created a new method.),这一点可以通过添加@override来求证(error: method does not override or implement a method from a supertype),所以final+private相比private,不会有什么额外效果。

final修饰类

这个类无法被继承。类中的属性可以为final的,也可以不为final。

类的加载

构造函数也算是static方法。
一个类只有在static成员被首次访问时才加载(尽可能地lazy)。一个例外是static final的常数,不会引起类加载。
编译后的.class在需要时才会被加载。

static对象和代码块的加载

按照代码顺序进行加载,只加载一次。

考虑继承时,初始化全过程

首先,仍然是“使用时加载”的原则;
加载一个类时,如果它有父类,则也加载父类,依次类推;
当不再有父类时,辈分最高的类进行static初始化,然后是其子类,依此类推(因为子类的static初始化依赖于父类的static初始化);
做好上述准备后,创建类的对象,首先是基本类型和对象类型赋默认初值;
递归调用父类的构造函数;
成员按代码赋初值;
调用构造函数的剩余部分。

总结一下:
代码加载;static初始化;分配置零内存;父类构造函数;本类成员初始化;本类构造函数。

多态(又名动态绑定/运行时绑定/晚绑定)

inheritance enabled you to treat an object as its own type or its base type. This treats many types (derived from the same base type) as if they were one type, and a single piece of code works on all those different types equally.
我的理解是,继承是子类替换父类,多态是兄弟类(甚至叔侄)互相替换。
以父类为入参时,我们无法确定入参到底是父类,还是父类的哪一个子类,只有运行时才能确定。这就是动态绑定。这样可以显著减少函数的数量(不用为每一个子类类型写一个函数),有点“一生万物”的感觉。

除了减少代码量
多态的好处还有易扩展,可以在不修改以父类为参数的函数的情况下,自由添加子类,乃至子类的子类(比如shape的draw的例子,不仅可以添加三角形,还可以添加三角形的子类等边三角形,而shape基类的draw方法始终无需修改)。

除了static方法(构造函数’re actually static methods, but the static declaration is implicit)和private方法,Java中所有方法都默认动态绑定(不像C++要声明virtual)。

构造函数中应该避免使用当前类还没有初始化的东西,避免使用当前类的方法。构造函数中唯一安全的函数是父类中的final/private函数。

多态的例外

如果函数只是返回父类的一个public成员,那么就不存在动态绑定。
In this example, different storage is allocated for Super.field and Sub.field. Thus, Sub actually contains two fields called field: its own and the one it gets from Super. However, the Super version is not the default that is produced when you refer to field in Sub. To get the Super field you must explicitly say super.field.
子类中不应该再声明一个与父类public成员同名的成员。如果的确这么做了,那么默认使用子类的。

object类的方法

方法名作用
protected Object clone()创建并返回此对象的一个副本
boolean equals(Object obj)指示其他某个对象是否与此对象“相等”
protected void finalize()当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法
Class<?> getClass()返回此 Object 的运行时类
int hashCode()返回该对象的哈希码值
void notify()唤醒在此对象监视器上等待的单个线程
void notifyAll()唤醒在此对象监视器上等待的所有线程
String toString()返回该对象的字符串表示
void wait()在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待
void wait(long timeout)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待
void wait(long timeout, int nanos)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待

toString的默认实现:类名+hashCode()生成的的无符号十六进制数
equal的默认实现:比较两个对象的地址

如何写一个自己的equal函数

  1. If the rval is null, it’s not equal.
  2. If the rval is this (you’re comparing yourself to yourself), the two objects are equal.
  3. If the rval is not the same class or subclass, the two objects are not equal.
  4. If all the above checks pass, then you must decide which fields in the rval are important (and consistent), and compare those.
    依照上述原则的代码示例:
public boolean equals(Object rval) {
	if(rval == null)
		return false;
	if(rval == this)
		return true;
	if(!(rval instanceof Equality))
		return false;
	Equality other = (Equality)rval;
	if(!Objects.equals(i, other.i))
		return false;
	if(!Objects.equals(s, other.s))
		return false;
	if(!Objects.equals(d, other.d))
		return false;
	return true;
}

guava

接近生产代码的demo

public class NonNullConstruction {
	private Integer n;
	private String s;
	NonNullConstruction(Integer n, String s) {
		this.n = checkNotNull(n);
		this.s = checkNotNull(s);
	}
}

接近教科书的demo

import java.util.function.*;
import static com.google.common.base.Preconditions.*;

public class GuavaPreconditions {
	static void test(Consumer<String> c, String s) {
	//我所理解的Consumer<String>就是一个以string为入参的函数
	//accept,就是将参数传给consumer,并执行consumer的内容。
		try {
			System.out.println(s);
			c.accept(s);
			System.out.println("Success");
		} catch(Exception e) {
			String type = e.getClass().getSimpleName();
			String msg = e.getMessage();
			System.out.println(type + (msg == null ? "" : ": " + msg));
		}
	}

	public static void main(String[] args) {
	//test的三种重载,由于效率问题,第三种的replace限定为字符串类型
		test(s -> s = checkNotNull(s), "X");
		test(s -> s = checkNotNull(s, "s was null"), null);
		test(s -> s = checkNotNull(s, "s was null, %s %s", "arg2", "arg3"), null);
	// checkArgument的使用
		test(s -> checkArgument(s == "Fozzie"), "Fozzie");
	// checkState的使用
		test(s -> checkState(s.length() > 6), "Mortimer");
	// checkElementIndex, checkPositionIndex, checkPositionIndexes的使用
	// 前两者区别在于小于和小于等于,第三者则是下限非负,上限小于等于
		test(s ->checkElementIndex(6, s.length()), "Robert");
		test(s ->checkPositionIndex(6, s.length()), "Robert");
		test(s -> checkPositionIndexes(0, 6, s.length()), "Hieronymus");
	}


Annotation

注解的优势在于整洁。
注解是一种元数据。趋势是,将元数据与源代码放在一起,而不是将元数据放在外部文件中。
Annotation的设计初衷,就是能生成描述性文件(如javadoc,以及一些框架需要外部xml),以及能生成新的类从而减少套路代码(如lombok)。
从使用上来说,注解类似public、void这样的modifier。

从定义上来说,注解类似接口。而且注解在编译后也会生成.class。区别在于,需要指定target(方法或field)和retention(源代码,class,运行时)等Meta-annotation(也就是注解的注解,共有五个)。

import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
	int id();
	String description() default "no description";
}

此处的id和description,就是我们见到的annotation括号里可以被赋值的属性。属性的类型比较有限,基本类型、字符串、class、枚举、注解、array。通过id()就能取到id。

为什么叫元数据?当注解用于方法的时候,感觉并不贴切,但当注解用于field、局部变量的时候,就是对数据的一种描述了:

public class Member {
	@SQLString(30) String firstName;
	@SQLInteger Integer age;
	@SQLString(value = 30,
constraints = @Constraints(primaryKey = true))
String reference;
	//...

上面代码的完整版可以通过自己写的annotation processor来自动生成建表sql语句。
通过继承AbstractProcessor,原书实现了一些processor。通过javac可以调用这些processor,可以看见生成的class。

上面的是我的项目结构,现在我想要加入开源的通义大模型,实现项目具有以下功能 自行准备本地知识库资料(如本专业相关资料内容)作为大模型本地知识库的输入 教师侧:备课与设计: 根据所提供的本地课程大纲、课程知识库文档等自动设计教学内容,包括知识讲解、实训练习与指导、时间分布等。 · 考核内容生成: 根据教学内容自动生成考核题目及参考答案,考核题目种类可多样化,根据学科设计,如计算机类可设计相关编程题和答案 · 学情数据分析: 对学生提交的答案进行自动化检测,提供错误定位与修正建议。对学生整体数据进行分析,总结知识掌握情况与教学建议。 学生侧: · 在线学习助手: 对学生的提出的问题,结合教学内容进行解答; · 实时练习评测助手: 根据学生历史练习情况,以及学生的练习要求,生成随练题目,并对练习纠错。 管理侧: 用户管理:管理员/教师/学生等用户的基本管理 课件资源管理:按学科列表教师备课产生的课件、练习等资源,可以导出。 大屏概览: · 教师使用次数统计/活跃板块(当日/本周) · 学生使用次数统计/活跃板块(当日/本周) · 教学效率指数(备课与修正耗时、课后练习设计与修正耗时、课程优化方向(如:某学科通过率持续偏低) · 学生学习效果(平均正确率趋势、知识点掌握情况,高频错误知识点等) 非功能性需求 需明确使用至少1个开源大模型作为核心技术组件; 需采用本地知识库作为输入,知识库资料总量不大于100M; 生成的内容、练习与答案与本地知识库的关联性和准确性;(对抽取知识点设计的题目验证关联性和与答案的准确性有知识点说明) 我该在哪里添加 下面我再对功能进行进一步的说明:1、首先本地知识库可以让用户自己上传(即用户自己可以控制本地知识库,但一开始会有一个默认的知识库,知识库是在项目中的某个目录中可以吗), 2、在备课与设计的功能上ai可以帮助教师设计教学内容,并且教师可以下载该教学内容 3、在考核内容生成中,考核题目同样可以进行下载,而且可以有带答案不带答案两种方式; 完整的项目结构又是怎样的,哪些内容需要更改 下面是我目前的项目结构卷 Windows-SSD 的文件夹 PATH 列表 卷序列号为 20C7-404E C:. | project_structure.txt | +---main | +---java | | \---com | | | Aiapp1Application.java | | | | | +---annotation | | | APPLoginUser.java | | | IgnoreAuth.java | | | LoginUser.java | | | | | +---config | | | InterceptorConfig.java | | | MybatisPlusConfig.java | | | MyMetaObjectHandler.java | | | | | +---controller | | | CommonController.java | | | ConfigController.java | | | DictionaryController.java | | | ExampaperController.java | | | ExamquestionController.java | | | ExamrecordController.java | | | ExamredetailsController.java | | | ExamrewrongquestionController.java | | | FileController.java | | | ForumController.java | | | JiaoshiController.java | | | KechengController.java | | | KechengLiuyanController.java | | | NewsController.java | | | UsersController.java | | | YonghuController.java | | | | | +---dao | | | CommonDao.java | | | ConfigDao.java | | | DictionaryDao.java | | | ExampaperDao.java | | | ExamquestionDao.java | | | ExamrecordDao.java | | | ExamredetailsDao.java | | | ExamrewrongquestionDao.java | | | ForumDao.java | | | JiaoshiDao.java | | | KechengDao.java | | | KechengLiuyanDao.java | | | NewsDao.java | | | TokenDao.java | | | UsersDao.java | | | YonghuDao.java | | | | | +---entity | | | | ConfigEntity.java | | | | DictionaryEntity.java | | | | EIException.java | | | | ExampaperEntity.java | | | | ExamquestionEntity.java | | | | ExamrecordEntity.java | | | | ExamredetailsEntity.java | | | | ExamrewrongquestionEntity.java | | | | ForumEntity.java | | | | JiaoshiEntity.java | | | | KechengEntity.java | | | | KechengLiuyanEntity.java | | | | NewsEntity.java | | | | TokenEntity.java | | | | UsersEntity.java | | | | YonghuEntity.java | | | | | | | +---model | | | | DictionaryModel.java | | | | ExampaperModel.java | | | | ExamquestionModel.java | | | | ExamrecordModel.java | | | | ExamredetailsModel.java | | | | ExamrewrongquestionModel.java | | | | ForumModel.java | | | | JiaoshiModel.java | | | | KechengLiuyanModel.java | | | | KechengModel.java | | | | NewsModel.java | | | | YonghuModel.java | | | | | | | +---view | | | | DictionaryView.java | | | | ExampaperView.java | | | | ExamquestionView.java | | | | ExamrecordView.java | | | | ExamredetailsView.java | | | | ExamrewrongquestionView.java | | | | ForumView.java | | | | JiaoshiView.java | | | | KechengLiuyanView.java | | | | KechengView.java | | | | NewsView.java | | | | YonghuView.java | | | | | | | \---vo | | | DictionaryVO.java | | | ExampaperVO.java | | | ExamquestionVO.java | | | ExamrecordVO.java | | | ExamredetailsVO.java | | | ExamrewrongquestionVO.java | | | ForumVO.java | | | JiaoshiVO.java | | | KechengLiuyanVO.java | | | KechengVO.java | | | NewsVO.java | | | YonghuVO.java | | | | | +---interceptor | | | AuthorizationInterceptor.java | | | | | +---model | | | \---enums | | | TypeEnum.java | | | | | +---service | | | | CommonService.java | | | | ConfigService.java | | | | DictionaryService.java | | | | ExampaperService.java | | | | ExamquestionService.java | | | | ExamrecordService.java | | | | ExamredetailsService.java | | | | ExamrewrongquestionService.java | | | | ForumService.java | | | | JiaoshiService.java | | | | KechengLiuyanService.java | | | | KechengService.java | | | | NewsService.java | | | | TokenService.java | | | | UsersService.java | | | | YonghuService.java | | | | | | | \---impl | | | CommonServiceImpl.java | | | ConfigServiceImpl.java | | | DictionaryServiceImpl.java | | | ExampaperServiceImpl.java | | | ExamquestionServiceImpl.java | | | ExamrecordServiceImpl.java | | | ExamredetailsServiceImpl.java | | | ExamrewrongquestionServiceImpl.java | | | ForumServiceImpl.java | | | JiaoshiServiceImpl.java | | | KechengLiuyanServiceImpl.java | | | KechengServiceImpl.java | | | NewsServiceImpl.java | | | TokenServiceImpl.java | | | UsersServiceImpl.java | | | YonghuServiceImpl.java | | | | | +---ServletContextListener | | | DictionaryServletContextListener.java | | | | | +---thread | | | MyThreadMethod.java | | | | | \---utils | | BaiduUtil.java | | CommonUtil.java | | FileUtil.java | | HttpClientUtils.java | | JQPageInfo.java | | MPUtil.java | | PageUtils.java | | PoiUtil.java | | Query.java | | R.java | | SpringContextUtils.java | | SQLFilter.java | | StringUtil.java | | ValidatorUtils.java | | | \---resources | | application.yml | | | +---front | | | index.html | | | | | +---css | | | bootstrap.min.css | | | common.css | | | front-kaoshi-style.css | | | homeworkPC.min.css | | | style.css | | | theme.css | | | | | +---elementui | | | | elementui.css | | | | elementui.js | | | | | | | \---fonts | | | element-icons.ttf | | | element-icons.woff | | | | | +---img | | | avator.png | | | banner.jpg | | | jianshe.png | | | jiaotong.png | | | line.jpg | | | nongye.png | | | seckilling.jpg | | | select.png | | | selectActive.png | | | unselect.png | | | weixin.png | | | yuan.png | | | zhifubao.png | | | zhongguo.png | | | | | +---js | | | bootstrap.AMapPositionPicker.js | | | bootstrap.min.js | | | config.js | | | jquery.js | | | utils.js | | | validate.js | | | vue.js | | | | | +---layui | | | | layui.all.js | | | | layui.js | | | | | | | +---css | | | | | layui.css | | | | | layui.mobile.css | | | | | | | | | \---modules | | | | | code.css | | | | | | | | | +---laydate | | | | | \---default | | | | | laydate.css | | | | | | | | | \---layer | | | | \---default | | | | icon-ext.png | | | | icon.png | | | | layer.css | | | | loading-0.gif | | | | loading-1.gif | | | | loading-2.gif | | | | | | | +---font | | | | iconfont.eot | | | | iconfont.svg | | | | iconfont.ttf | | | | iconfont.woff | | | | iconfont.woff2 | | | | | | | +---images | | | | \---face | | | | 0.gif | | | | 1.gif | | | | 10.gif | | | | 11.gif | | | | 12.gif | | | | 13.gif | | | | 14.gif | | | | 15.gif | | | | 16.gif | | | | 17.gif | | | | 18.gif | | | | 19.gif | | | | 2.gif | | | | 20.gif | | | | 21.gif | | | | 22.gif | | | | 23.gif | | | | 24.gif | | | | 25.gif | | | | 26.gif | | | | 27.gif | | | | 28.gif | | | | 29.gif | | | | 3.gif | | | | 30.gif | | | | 31.gif | | | | 32.gif | | | | 33.gif | | | | 34.gif | | | | 35.gif | | | | 36.gif | | | | 37.gif | | | | 38.gif | | | | 39.gif | | | | 4.gif | | | | 40.gif | | | | 41.gif | | | | 42.gif | | | | 43.gif | | | | 44.gif | | | | 45.gif | | | | 46.gif | | | | 47.gif | | | | 48.gif | | | | 49.gif | | | | 5.gif | | | | 50.gif | | | | 51.gif | | | | 52.gif | | | | 53.gif | | | | 54.gif | | | | 55.gif | | | | 56.gif | | | | 57.gif | | | | 58.gif | | | | 59.gif | | | | 6.gif | | | | 60.gif | | | | 61.gif | | | | 62.gif | | | | 63.gif | | | | 64.gif | | | | 65.gif | | | | 66.gif | | | | 67.gif | | | | 68.gif | | | | 69.gif | | | | 7.gif | | | | 70.gif | | | | 71.gif | | | | 8.gif | | | | 9.gif | | | | | | | \---lay | | | \---modules | | | carousel.js | | | code.js | | | colorpicker.js | | | element.js | | | flow.js | | | form.js | | | jquery.js | | | laydate.js | | | layedit.js | | | layer.js | | | laypage.js | | | laytpl.js | | | mobile.js | | | rate.js | | | slider.js | | | table.js | | | transfer.js | | | tree.js | | | upload.js | | | util.js | | | | | +---modules | | | | config.js | | | | | | | +---http | | | | http.js | | | | | | | +---layarea | | | | layarea.js | | | | | | | \---tinymce | | | | index.html | | | | tinymce.js | | | | | | | \---tinymce | | | | jquery.tinymce.min.js | | | | license.txt | | | | readme.md | | | | tinymce.js | | | | tinymce.min.js | | | | | | | +---langs | | | | readme.md | | | | zh_CN.js | | | | | | | +---plugins | | | | +---advlist | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---anchor | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---autolink | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---autoresize | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---autosave | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---bbcode | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---charmap | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---code | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---codesample | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---colorpicker | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---contextmenu | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---directionality | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---emoticons | | | | | | plugin.js | | | | | | plugin.min.js | | | | | | | | | | | \---js | | | | | emojis.js | | | | | emojis.min.js | | | | | | | | | +---fullpage | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---fullscreen | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---help | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---hr | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---image | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---imagetools | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---importcss | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---indent2em | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---insertdatetime | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---legacyoutput | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---link | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---lists | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---media | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---nonbreaking | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---noneditable | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---pagebreak | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---paste | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---preview | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---print | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---quickbars | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---save | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---searchreplace | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---spellchecker | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---tabfocus | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---table | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---template | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---textcolor | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---textpattern | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---toc | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---visualblocks | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---visualchars | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | \---wordcount | | | | plugin.js | | | | plugin.min.js | | | | | | | +---skins | | | | +---content | | | | | +---dark | | | | | | content.css | | | | | | content.min.css | | | | | | content.min.css.map | | | | | | | | | | | +---default | | | | | | content.css | | | | | | content.min.css | | | | | | content.min.css.map | | | | | | | | | | | +---document | | | | | | content.css | | | | | | content.min.css | | | | | | content.min.css.map | | | | | | | | | | | \---writer | | | | | content.css | | | | | content.min.css | | | | | content.min.css.map | | | | | | | | | \---ui | | | | +---oxide | | | | | | content.css | | | | | | content.inline.css | | | | | | content.inline.min.css | | | | | | content.inline.min.css.map | | | | | | content.min.css | | | | | | content.min.css.map | | | | | | content.mobile.css | | | | | | content.mobile.min.css | | | | | | content.mobile.min.css.map | | | | | | skin.css | | | | | | skin.min.css | | | | | | skin.min.css.map | | | | | | skin.mobile.css | | | | | | skin.mobile.min.css | | | | | | skin.mobile.min.css.map | | | | | | | | | | | \---fonts | | | | | tinymce-mobile.woff | | | | | | | | | \---oxide-dark | | | | | content.css | | | | | content.inline.css | | | | | content.inline.min.css | | | | | content.inline.min.css.map | | | | | content.min.css | | | | | content.min.css.map | | | | | content.mobile.css | | | | | content.mobile.min.css | | | | | content.mobile.min.css.map | | | | | skin.css | | | | | skin.min.css | | | | | skin.min.css.map | | | | | skin.mobile.css | | | | | skin.mobile.min.css | | | | | skin.mobile.min.css.map | | | | | | | | | \---fonts | | | | tinymce-mobile.woff | | | | | | | \---themes | | | +---mobile | | | | theme.js | | | | theme.min.js | | | | | | | \---silver | | | theme.js | | | theme.min.js | | | | | +---pages | | | +---chat | | | | chat.html | | | | | | | +---dictionary | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---exampaper | | | | add.html | | | | detail.html | | | | exam.html | | | | list.html | | | | | | | +---examquestion | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---examrecord | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---examredetails | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---examrewrongquestion | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---forum | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---home | | | | home.html | | | | | | | +---jiaoshi | | | | add.html | | | | center.html | | | | detail.html | | | | list.html | | | | register.html | | | | | | | +---kecheng | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---kechengLiuyan | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---login | | | | login.html | | | | | | | +---news | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---recharge | | | | recharge.html | | | | | | | \---yonghu | | | add.html | | | center.html | | | detail.html | | | list.html | | | register.html | | | | | \---xznstatic | | +---css | | | | bootstrap.min.css | | | | common.css | | | | element.min.css | | | | login.css | | | | public.css | | | | style.css | | | | swiper.min.css | | | | | | | \---fonts | | | element-icons.ttf | | | element-icons.woff | | | | | +---img | | | 162237296.jpg | | | 162240878.jpg | | | 19.jpg | | | 1_092ZZ2503138.jpg | | | 20.jpg | | | index_24.gif | | | index_35.gif | | | index_41.gif | | | index_44.gif | | | logo.png | | | news_list_time.jpg | | | service_btn.png | | | service_img.png | | | service_title.png | | | | | \---js | | bootstrap.min.js | | element.min.js | | index.js | | jquery-1.11.3.min.js | | jquery.SuperSlide.2.1.1.js | | swiper.min.js | | | +---img | | \---img | | back-img-bg.jpg | | front-img-bg.jpg | | logo.jpg | | | +---mapper | | CommonDao.xml | | ConfigDao.xml | | DictionaryDao.xml | | ExampaperDao.xml | | ExamquestionDao.xml | | ExamrecordDao.xml | | ExamredetailsDao.xml | | ExamrewrongquestionDao.xml | | ForumDao.xml | | JiaoshiDao.xml | | KechengDao.xml | | KechengLiuyanDao.xml | | NewsDao.xml | | TokenDao.xml | | UsersDao.xml | | YonghuDao.xml | | | +---static | | +---admin | | | | 1-install.bat | | | | 2-run.bat | | | | 3-build.bat | | | | babel.config.js | | | | package-lock.json | | | | package.json | | | | vue.config.js | | | | | | | +---dist | | | | | favicon.ico | | | | | index.html | | | | | | | | | +---css | | | | | app.381d2044.css | | | | | chunk-vendors.a72b0961.css | | | | | | | | | +---fonts | | | | | element-icons.535877f5.woff | | | | | element-icons.732389de.ttf | | | | | | | | | +---img | | | | | 404.3648f234.png | | | | | zhongguo.20798bfa.png | | | | | | | | | \---js | | | | app.b100d28f.js | | | | app.b100d28f.js.map | | | | chunk-vendors.213b68ba.js | | | | chunk-vendors.213b68ba.js.map | | | | | | | +---public | | | | favicon.ico | | | | index.html | | | | | | | \---src | | | | App.vue | | | | main.js | | | | | | | +---assets | | | | +---css | | | | | element-variables.scss | | | | | style.scss | | | | | | | | | \---img | | | | | 404.png | | | | | avator.png | | | | | bg.jpg | | | | | captcha.jpg | | | | | login.png | | | | | logo.png | | | | | password.png | | | | | role.png | | | | | username.png | | | | | | | | | \---test | | | | jianshe.png | | | | jiaotong.png | | | | nongye.png | | | | weixin.png | | | | zhifubao.png | | | | zhongguo.png | | | | | | | +---components | | | | +---common | | | | | BreadCrumbs.vue | | | | | Editor.vue | | | | | FileUpload.vue | | | | | | | | | +---home | | | | | HomeCard.vue | | | | | HomeChart.vue | | | | | HomeComment.vue | | | | | HomeProgress.vue | | | | | | | | | +---index | | | | | IndexAside.vue | | | | | IndexAsideStatic.vue | | | | | IndexAsideSub.vue | | | | | IndexHeader.vue | | | | | IndexMain.vue | | | | | | | | | \---SvgIcon | | | | index.vue | | | | | | | +---icons | | | | | index.js | | | | | svgo.yml | | | | | | | | | \---svg | | | | | 404.svg | | | | | articleEdit.svg | | | | | banner.svg | | | | | bug.svg | | | | | build.svg | | | | | cfg.svg | | | | | channel.svg | | | | | chart.svg | | | | | clipboard.svg | | | | | code.svg | | | | | component.svg | | | | | contacts.svg | | | | | dashboard.svg | | | | | date.svg | | | | | dept.svg | | | | | dict.svg | | | | | documentation.svg | | | | | download.svg | | | | | drag.svg | | | | | druid.svg | | | | | edit.svg | | | | | education.svg | | | | | email.svg | | | | | excel.svg | | | | | exit-fullscreen.svg | | | | | eye-open.svg | | | | | file.svg | | | | | form.svg | | | | | fullscreen.svg | | | | | icon.svg | | | | | international.svg | | | | | job.svg | | | | | language.svg | | | | | link.svg | | | | | list.svg | | | | | lock.svg | | | | | log.svg | | | | | logininfor.svg | | | | | menu.svg | | | | | message.svg | | | | | money.svg | | | | | monitor.svg | | | | | nested.svg | | | | | nested0.svg | | | | | online.svg | | | | | operation.svg | | | | | password.svg | | | | | password0.svg | | | | | pdf.svg | | | | | people.svg | | | | | peoples.svg | | | | | phone.svg | | | | | post.svg | | | | | qq.svg | | | | | search.svg | | | | | sender.svg | | | | | server.svg | | | | | shopping.svg | | | | | shoppingCard.svg | | | | | size.svg | | | | | skill.svg | | | | | star.svg | | | | | swagger.svg | | | | | system.svg | | | | | tab.svg | | | | | table.svg | | | | | table0.svg | | | | | task.svg | | | | | template.svg | | | | | theme.svg | | | | | tool.svg | | | | | tree-table.svg | | | | | tree.svg | | | | | user.svg | | | | | user0.svg | | | | | validCode.svg | | | | | wechat.svg | | | | | zip.svg | | | | | | | | | \---svg | | | | agricultureRegister.svg | | | | AI.svg | | | | AIDeviceLayout.svg | | | | area.svg | | | | base.svg | | | | batch.svg | | | | board.svg | | | | board1.svg | | | | boardConfig.svg | | | | cfg.svg | | | | code.svg | | | | company.svg | | | | crop.svg | | | | crops.svg | | | | dashboard.svg | | | | dataAbnormal.svg | | | | dataLack.svg | | | | dept.svg | | | | device.svg | | | | deviceMonitorData.svg | | | | dict.svg | | | | diseasesinsect.svg | | | | diseasesinsects.svg | | | | documentation.svg | | | | EIM.svg | | | | email.svg | | | | environmental.svg | | | | eye-open.svg | | | | farmingProject.svg | | | | finance.svg | | | | financeBudget.svg | | | | financeReality.svg | | | | firm.svg | | | | firms.svg | | | | harvestBatch.svg | | | | harvestDetection.svg | | | | harvestManage.svg | | | | harvestWorks.svg | | | | heavyMetalDetection.svg | | | | home.svg | | | | inspection.svg | | | | internet.svg | | | | internetActive.svg | | | | log.svg | | | | mainSystem.svg | | | | mainSystemActive.svg | | | | menu.svg | | | | monitorEquipment.svg | | | | news.svg | | | | order.svg | | | | password.svg | | | | peoples.svg | | | | pest.svg | | | | pestActive.svg | | | | pesticideResidue.svg | | | | pests.svg | | | | phone.svg | | | | plant.svg | | | | plants.svg | | | | plantsActive.svg | | | | residual.svg | | | | retroactiveCoding.svg | | | | scheme.svg | | | | source.svg | | | | sourceActive.svg | | | | system.svg | | | | task.svg | | | | tempFarm.svg | | | | traceability.svg | | | | traceabilityList.svg | | | | traceabilityStyle.svg | | | | user.svg | | | | user0.svg | | | | validCode.svg | | | | video.svg | | | | videoEquipment.svg | | | | videoKey.svg | | | | VIP.svg | | | | vipCustomized.svg | | | | warnings.svg | | | | workOrder.svg | | | | ┐┤?х╣▄└э.svg | | | | ╓╪╜Ё╩?╝ь▓т╣▄└э.svg | | | | | | | +---router | | | | router-static.js | | | | | | | +---store | | | | store.js | | | | | | | +---utils | | | | api.js | | | | base.js | | | | http.js | | | | i18n.js | | | | menu.js | | | | storage.js | | | | style.css | | | | style.js | | | | utils.js | | | | validate.js | | | | | | | \---views | | | | 404.vue | | | | center.vue | | | | home.vue | | | | index.vue | | | | login.vue | | | | pay.vue | | | | register.vue | | | | update-password.vue | | | | | | | \---modules | | | +---config | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionary | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionaryExampaper | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionaryExamquestion | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionaryForumState | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionaryKecheng | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionaryNews | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionarySex | | | | add-or-update.vue | | | | list.vue | | | | | | | +---exampaper | | | | add-or-update.vue | | | | exam.vue | | | | list.vue | | | | | | | +---examquestion | | | | add-or-update.vue | | | | list.vue | | | | | | | +---examrecord | | | | add-or-update.vue | | | | list.vue | | | | | | | +---examredetails | | | | add-or-update.vue | | | | list.vue | | | | | | | +---examrewrongquestion | | | | add-or-update.vue | | | | list.vue | | | | | | | +---forum | | | | add-or-update.vue | | | | list.vue | | | | | | | +---jiaoshi | | | | add-or-update.vue | | | | list.vue | | | | | | | +---kecheng | | | | add-or-update.vue | | | | list.vue | | | | | | | +---kechengLiuyan | | | | add-or-update.vue | | | | list.vue | | | | | | | +---news | | | | add-or-update.vue | | | | list.vue | | | | | | | +---users | | | | add-or-update.vue | | | | list.vue | | | | | | | \---yonghu | | | add-or-update.vue | | | list.vue | | | | | \---upload | | a.txt | | config1.jpg | | config2.jpg | | config3.jpg | | file.rar | | jiaoshi.xls | | jiaoshi1.jpg | | jiaoshi2.jpg | | jiaoshi3.jpg | | jiaoshi4.jpg | | jiaoshi5.jpg | | jiaoshi6.jpg | | kecheng1.jpg | | kecheng2.jpg | | kecheng3.jpg | | kecheng4.jpg | | kecheng5.jpg | | kecheng6.jpg | | music.mp3 | | news1.jpg | | news2.jpg | | news3.jpg | | news4.jpg | | news5.jpg | | news6.jpg | | video.mp4 | | yonghu1.jpg | | yonghu2.jpg | | yonghu3.jpg | | | \---templates \---test \---java \---com Aiapp1ApplicationTests.java
最新发布
07-15
<think>根据需求,我们需要在项目中集成开源大模型(如通义大模型)来实现教师侧的备课与设计、考核内容生成、学情数据分析,学生侧的在线学习助手和实时练习评测助手,以及管理侧的大屏概览等功能。同时,需要支持本地知识库的上传和管理。 ### 分析现有项目结构 当前项目是一个典型的Spring Boot应用,包含以下主要部分- `main/java/com/...`: 包含应用的主要Java代码,包括启动类、配置、控制器、实体、DAO、服务等。 - `main/resources`: 包含配置文件、前端资源、静态文件、MyBatis映射文件等。 - `test`: 测试代码。 ### 需要添加的功能模块 1. **大模型集成模块**:用于调用开源大模型(如通义)的API。 2. **本地知识库管理模块**:允许用户上传和管理知识库文件(默认知识库放在项目目录中,如`resources/knowledge`)。 3. **教师侧功能**: - 备课与设计:根据知识库生成教学内容(包括知识讲解、实训、时间分布等),并提供下载。 - 考核内容生成:生成题目和答案,支持下载(带答案和不带答案)。 4. **学生侧功能**: - 在线学习助手:回答学生问题,结合知识库和教学内容。 - 实时练习评测:生成练习题,并自动批改和纠错。 5. **管理侧功能**: - 用户管理(已有,可能需要扩展)。 - 课件资源管理:管理教师生成的课件和练习,支持导出。 - 大屏概览:统计教师和学生的使用情况,教学效率,学习效果等。 ### 项目结构调整建议 1. **在`com`包下新建包`ai`**,用于存放与大模型交互相关的代码。 - `service`: 大模型服务接口和实现。 - `controller`: 提供AI相关接口(如生成教学内容、题目等)。 - `utils`: 大模型调用工具类。 2. **知识库存储**: - 默认知识库:放在`resources/knowledge`目录下,项目启动时加载。 - 用户上传知识库:存储在服务器文件系统中(如`upload/knowledge`),并在数据库中记录知识库文件信息(可能需要新建实体和表)。 3. **教师侧功能**: - 在`controller`包下新建`TeacherAIController`,处理备课、生成题目等请求。 - 在`service`包下新建`TeacherAIService`,实现调用大模型生成教学内容和题目的逻辑。 4. **学生侧功能**: - 在`controller`包下新建`StudentAIController`,处理学生提问和练习评测请求。 - 在`service`包下新建`StudentAIService`,实现问题解答和练习评测逻辑。 5. **管理侧功能**: - 课件资源管理:在现有的`FileController`中增加对课件资源的管理,或新建`ResourceController`。 - 大屏概览:新建`DashboardController`,提供统计数据接口。 6. **数据库调整**: - 可能需要新增表来存储生成的教学内容、题目、答案、练习记录等。 - 例如:`teaching_content`, `exam_question`, `practice_record`等。 7. **前端调整**: - 在`resources/front/pages`下新增教师备课、学生练习等页面。 - 在管理后台的前端(`static/admin`)中添加课件资源管理和大屏概览的页面。 ### 代码示例 #### 1. 大模型服务接口 在`com.ai.service`包下创建`AIService`接口和实现类`AIServiceImpl`,用于封装大模型调用。 ```java package com.ai.service; public interface AIService { String generateTeachingContent(String knowledgeBase, String courseOutline); String generateExamQuestions(String knowledgeBase, int questionCount, boolean withAnswers); String answerQuestion(String question, String context); String generatePracticeExercise(String userId, String history); String evaluateAnswer(String answer, String correctAnswer); } ``` #### 2. 实现类(示例使用通义大模型,假设有对应的SDK) 这里假设我们使用HTTP API调用通义大模型,具体URL和参数需根据通义文档调整。 ```java package com.ai.service.impl; import com.ai.service.AIService; import com.utils.HttpClientUtils; import org.springframework.stereotype.Service; @Service public class AIServiceImpl implements AIService { private static final String TONGYI_API_URL = "https://api.tongyi.com/v1/chat/completions"; private static final String API_KEY = "your_api_key"; @Override public String generateTeachingContent(String knowledgeBase, String courseOutline) { String prompt = "根据以下知识库和课程大纲,设计教学内容:\n知识库:" + knowledgeBase + "\n课程大纲:" + courseOutline; return callTongyiAPI(prompt); } @Override public String generateExamQuestions(String knowledgeBase, int questionCount, boolean withAnswers) { String prompt = "根据以下知识库生成" + questionCount + "道题目" + (withAnswers ? "并附答案" : "") + ":\n" + knowledgeBase; return callTongyiAPI(prompt); } @Override public String answerQuestion(String question, String context) { String prompt = "问题:" + question + "\n上下文:" + context + "\n请回答:"; return callTongyiAPI(prompt); } @Override public String generatePracticeExercise(String userId, String history) { // 根据用户历史练习情况生成练习题 String prompt = "根据用户" + userId + "的练习历史:" + history + ",生成一道练习题"; return callTongyiAPI(prompt); } @Override public String evaluateAnswer(String answer, String correctAnswer) { String prompt = "判断学生答案是否正确,并给出解析。学生答案:" + answer + "\n参考答案:" + correctAnswer; return callTongyiAPI(prompt); } private String callTongyiAPI(String prompt) { // 构造请求体,这里以通义API为例,实际根据API文档调整 String requestBody = "{\"model\":\"qwen-turbo\",\"messages\":[{\"role\":\"user\",\"content\":\"" + prompt + "\"}]}"; Map<String, String> headers = new HashMap<>(); headers.put("Authorization", "Bearer " + API_KEY); headers.put("Content-Type", "application/json"); try { String response = HttpClientUtils.post(TONGYI_API_URL, requestBody, headers); // 解析响应,这里假设返回的JSON中choices[0].message.content是回答 // 实际解析需要根据通义API返回结构 JSONObject jsonResponse = new JSONObject(response); return jsonResponse.getJSONArray("choices").getJSONObject(0).getJSONObject("message").getString("content"); } catch (Exception e) { e.printStackTrace(); return "调用大模型失败"; } } } ``` #### 3. 教师侧控制器 在`com.controller`包下创建`TeacherAIController`: ```java package com.controller; import com.ai.service.AIService; import com.utils.R; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/ai/teacher") public class TeacherAIController { @Autowired private AIService aiService; @PostMapping("/generateContent") public R generateContent(String courseOutline) { // 从默认知识库或用户上传的知识库中读取内容(这里简化,实际需要从数据库或文件中读取) String knowledgeBase = "从知识库中读取的内容"; String content = aiService.generateTeachingContent(knowledgeBase, courseOutline); return R.ok().put("content", content); } @PostMapping("/generateExam") public R generateExam(int questionCount, boolean withAnswers) { String knowledgeBase = "从知识库中读取的内容"; String exam = aiService.generateExamQuestions(knowledgeBase, questionCount, withAnswers); return R.ok().put("exam", exam); } } ``` #### 4. 学生侧控制器 在`com.controller`包下创建`StudentAIController`: ```java package com.controller; import com.ai.service.AIService; import com.utils.R; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/ai/student") public class StudentAIController { @Autowired private AIService aiService; @PostMapping("/ask") public R askQuestion(String question) { // 结合当前课程的知识库内容作为上下文 String context = "相关知识点上下文"; String answer = aiService.answerQuestion(question, context); return R.ok().put("answer", answer); } @PostMapping("/generatePractice") public R generatePractice(String userId) { // 获取用户历史练习记录 String history = "用户历史练习记录"; String exercise = aiService.generatePracticeExercise(userId, history); return R.ok().put("exercise", exercise); } @PostMapping("/evaluate") public R evaluateAnswer(String answer, String correctAnswer) { String result = aiService.evaluateAnswer(answer, correctAnswer); return R.ok().put("result", result); } } ``` #### 5. 知识库管理 在`FileController`中增加知识库上传接口,或新建`KnowledgeBaseController`。 ```java // 在FileController中添加 @PostMapping("/uploadKnowledge") public R uploadKnowledge(@RequestParam("file") MultipartFile file) throws IOException { // 保存知识库文件到指定目录,如upload/knowledge // 记录到数据库,关联用户 return R.ok(); } ``` ### 数据库表设计建议 1. **知识库表(knowledge_base)**: - id, user_id, file_name, file_path, create_time 2. **教学内容表(teaching_content)**: - id, teacher_id, title, content, create_time 3. **题目表(exam_question)**: - id, content_id, question, answer, options (如果是选择题), type (题型), difficulty 4. **练习记录表(practice_record)**: - id, student_id, question_id, answer, is_correct, feedback, time ### 前端调整 - 教师备课页面:调用`/ai/teacher/generateContent`生成内容,并提供下载按钮(可生成Word或PDF)。 - 题目生成页面:调用`/ai/teacher/generateExam`生成题目,提供下载(带答案和不带答案)。 - 学生提问页面:调用`/ai/student/ask`获取答案。 - 练习页面:调用`/ai/student/generatePractice`生成练习,提交后调用`/ai/student/evaluate`进行批改。 ### 注意事项 1. **大模型选择**:通义大模型需要申请API Key,注意API调用频率和费用。 2. **本地知识库处理**:上传的知识库文件需要解析(如TXT、PDF、Word等),提取文本供大模型使用。可以使用Apache Tika等工具。 3. **性能考虑**:大模型调用可能较慢,考虑异步处理(如使用Spring的@Async)。 4. **安全性**:对上传的文件进行安全检查,防止恶意文件。 ### 项目结构变化 - 新增`ai`包,包含大模型相关代码。 - 新增控制器`TeacherAIController`和`StudentAIController`。 - 新增数据库表(需在entity包下新增实体,并创建Mapper和Service)。 - 前端新增页面。 ### 默认知识库放置 在`resources`目录下创建`knowledge`文件夹,存放默认知识库文件。在应用启动时,可以加载这些文件到内存或数据库。 ### 相关依赖 在`pom.xml`中添加HTTP客户端(如OkHttp或Apache HttpClient)和JSON处理库(如fastjson)。 ```xml <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.9.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.78</version> </dependency> ``` ### 总结 以上方案将大模型集成到现有项目中,实现了教师备课、题目生成,学生问答和练习评测等功能。同时,通过文件上传管理知识库,并提供下载功能。需要根据实际的大模型API调整调用方式,并完善前后端交互。 §§相关问题§§: 1. 如何解析上传的PDF、Word等格式的知识库文件? 2. 如何设计数据库表来存储生成的教学内容和题目? 3. 如何实现异步调用大模型API以避免阻塞请求? 4. 如何保证大模型生成的内容与知识库的关联性和准确性?</think>为了将开源通义大模型集成到您的项目中,并实现所需功能,以下是详细的解决方案和项目结构调整建议: ### 1. 本地知识库管理 **实现方案:** - 在`resources`目录下创建`knowledge-base`文件夹存放默认知识- 新增知识库管理模块(实体、DAO、Service、Controller) - 实现文件上传接口管理用户上传的知识库 **代码示例:** `KnowledgeBaseController.java`: ```java @RestController @RequestMapping("/knowledge") public class KnowledgeBaseController { @Autowired private KnowledgeService knowledgeService; // 上传知识库文件 @PostMapping("/upload") public R uploadKnowledge(@RequestParam("file") MultipartFile file) { return knowledgeService.uploadKnowledge(file); } // 获取知识库列表 @GetMapping("/list") public R listKnowledge() { return knowledgeService.getKnowledgeList(); } } ``` `KnowledgeService.java`: ```java @Service public class KnowledgeService { @Value("${knowledge.base.path}") private String basePath; public R uploadKnowledge(MultipartFile file) { // 文件大小校验(<100MB) if (file.getSize() > 100 * 1024 * 1024) { return R.error("文件大小不能超过100MB"); } // 保存文件到知识库目录 String fileName = FileUtil.saveFile(file, basePath); // 保存记录到数据库 KnowledgeEntity entity = new KnowledgeEntity(); entity.setFileName(fileName); entity.setOriginalName(file.getOriginalFilename()); knowledgeDao.insert(entity); return R.ok().put("path", fileName); } } ``` ### 2. 教师备课功能集成 **实现方案:** - 新增`AIController`处理AI相关请求 - 集成通义大模型SDK(如通义千问) - 实现教学内容生成接口 **代码示例:** `AIController.java`: ```java @RestController @RequestMapping("/ai") public class AIController { @Autowired private AIService aiService; // 生成教学内容 @PostMapping("/generate-teaching-plan") public R generateTeachingPlan(@RequestBody TeachingPlanRequest request) { TeachingContent content = aiService.generateTeachingContent( request.getCourseId(), request.getKnowledgeIds() ); return R.ok().put("data", content); } } ``` `AIServiceImpl.java`: ```java @Service public class AIServiceImpl implements AIService { @Autowired private KnowledgeDao knowledgeDao; @Override public TeachingContent generateTeachingContent(Long courseId, List<Long> knowledgeIds) { // 1. 获取知识库内容 List<String> knowledgeContents = knowledgeDao.getContentsByIds(knowledgeIds); String context = String.join("\n\n", knowledgeContents); // 2. 构造大模型提示词 String prompt = "你是一名专业教师,请根据以下课程大纲和知识库内容设计教学方案:\n" + context + "\n\n" + "要求包含:知识讲解框架、实训练习设计、时间分配建议(总课时90分钟)"; // 3. 调用通义大模型API String aiResponse = TongyiClient.generateText(prompt); // 4. 解析响应并生成结构化教学内容 return TeachingContentParser.parse(aiResponse); } } ``` ### 3. 考核内容生成 **实现方案:** - 新增题目生成接口 - 支持带答案/不带答案两种模式 - 实现题目下载功能(PDF/Word) **代码示例:** `AIController.java` 新增: ```java // 生成考核题目 @PostMapping("/generate-exam") public R generateExamQuestions(@RequestBody ExamRequest request) { ExamContent exam = aiService.generateExam( request.getCourseId(), request.getQuestionTypes(), request.isIncludeAnswers() ); return R.ok().put("data", exam); } // 下载题目(PDF) @GetMapping("/download-exam/{examId}") public void downloadExam(@PathVariable Long examId, HttpServletResponse response) { ExamContent exam = examService.getExamById(examId); PdfUtil.generateExamPdf(exam, response); } ``` ### 4. 项目结构调整 需要新增/修改的模块: ``` src/main/java/com/ ├── ai │ ├── controller │ │ └── AIController.java │ ├── service │ │ ├── AIService.java │ │ └── impl │ │ └── AIServiceImpl.java │ └── client │ └── TongyiClient.java ├── knowledge │ ├── entity │ │ └── KnowledgeEntity.java │ ├── dao │ │ └── KnowledgeDao.java │ └── service │ └── KnowledgeService.java └── teaching ├── entity │ ├── TeachingContent.java │ └── ExamContent.java └── util └── PdfUtil.java ``` ### 5. 配置文件修改 `application.yml` 新增配置: ```yaml tongyi: api-key: YOUR_API_KEY endpoint: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation knowledge: base-path: classpath:knowledge-base/ max-size-mb: 100 ``` ### 6. 前端调整建议 1. 教师侧新增页面: - `resources/front/pages/teaching/ai-teaching-plan.html` 备课页面 - `resources/front/pages/exam/ai-exam-generator.html` 题目生成页面 2. 学生侧新增页面: - `resources/front/pages/learning/ai-assistant.html` 学习助手 - `resources/front/pages/practice/ai-practice.html` 智能练习 3. 管理侧新增: - `static/admin/src/views/modules/dashboard.vue` 教学数据大屏 - `static/admin/src/views/modules/knowledge` 知识库管理 ### 7. 通义大模型集成 **通义千问集成示例:** `TongyiClient.java`: ```java public class TongyiClient { private static final Logger logger = LoggerFactory.getLogger(TongyiClient.class); public static String generateText(String prompt) { OkHttpClient client = new OkHttpClient(); MediaType mediaType = MediaType.parse("application/json"); // 构造请求体 String json = "{\"model\":\"qwen-turbo\",\"input\":{\"messages\":[" + "{\"role\":\"system\",\"content\":\"你是一名专业助教\"}," + "{\"role\":\"user\",\"content\":\"" + prompt + "\"}]}}"; Request request = new Request.Builder() .url("https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation") .post(RequestBody.create(mediaType, json)) .addHeader("Authorization", "Bearer " + apiKey) .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); JSONObject jsonResponse = new JSONObject(response.body().string()); return jsonResponse.getJSONObject("output") .getJSONArray("choices") .getJSONObject(0) .getJSONObject("message") .getString("content"); } catch (Exception e) { logger.error("调用通义API失败", e); return "生成失败,请稍后重试"; } } } ``` ### 8. 非功能性需求实现 1. **知识库关联性验证**: ```java // 在生成题目后验证关联性 public void validateQuestionRelevance(Question question, List<Long> knowledgeIds) { List<String> knowledgePoints = knowledgeDao.getKeyPoints(knowledgeIds); String prompt = "请验证以下题目是否涉及这些知识点:\n知识点: " + String.join(",", knowledgePoints) + "\n题目: " + question.getContent(); String validation = TongyiClient.generateText(prompt); if (validation.contains("不相关")) { throw new ValidationException("生成题目与知识库关联性不足"); } } ``` 2. **教学效率指数计算**: ```sql -- 在DashboardController中使用的SQL SELECT AVG(TIMESTAMPDIFF(MINUTE, start_time, end_time)) AS avg_prep_time, SUM(CASE WHEN correctness < 60 THEN 1 ELSE 0 END) * 100.0 / COUNT(*) AS low_score_rate FROM teaching_sessions WHERE course_id = #{courseId} ``` ### 完整项目结构调整 ``` C:. ├── main │ ├── java │ │ └── com │ │ ├── ai │ │ ├── knowledge │ │ ├── teaching │ │ └── utils # 新增AI相关工具类 │ └── resources │ ├── knowledge-base # 知识库默认目录 │ ├── mapper │ │ └── KnowledgeDao.xml # 新增 │ └── templates │ └── exam-template.ftl # 考题模板 └── test └── java └── com └── ai └── AIServiceTest.java # 新增测试 ``` ### 关键注意事项 1. **知识库存储**: - 默认知识库:`resources/knowledge-base/` - 用户上传:存储在外部目录(如`/data/knowledge/`),避免打包时包含 2. **大模型调用优化**: - 使用异步调用避免阻塞:`@Async` - 实现结果缓存:`@Cacheable` - 添加限流保护:Resilience4j 3. **安全性**: - 知识库文件类型白名单(PDF/DOCX/TXT) - 文件内容病毒扫描 - API调用频率限制 4. **性能考虑**: - 大模型响应可能较慢(>5s),前端需要加载状态提示 - 大量知识库处理时分块调用API
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值