javaweb(四)——过滤器与监听器(下)

简介: javaweb(四)——过滤器与监听器

滤波器的性能评价


学习滤波器的性能评价方法,包括幅频特性曲线、相频特性曲线和群延迟曲线等。

滤波器的性能评价通常包括幅频特性曲线、相频特性曲线和群延迟曲线等。这些曲线可以帮助我们了解滤波器在不同频率下的频率响应特性,以及其对输入信号的影响。


1. 幅频特性曲线


幅频特性曲线是指滤波器的输出信号幅度与输入信号幅度之比随着频率变化的曲线。通常使用dB(分贝)单位来表示幅度比,因为dB具有对数特性,便于比较不同频率下的幅度响应。下面是一个简单的Java代码示例,展示如何绘制幅频特性曲线:

public class AmplitudeResponse {
    public static double[] amplitudeResponse(double[] b, double[] a, int N) {
        double[] H = new double[N];
        for (int i = 0; i < N; i++) {
            double w = Math.PI * i / N;
            Complex z = new Complex(Math.cos(w), Math.sin(w));
            Complex Hz = PolynomialUtils.evaluate(b, z).divide(PolynomialUtils.evaluate(a, z));
            H[i] = 20 * Math.log10(Hz.abs());
        }
        return H;
    }
    public static void main(String[] args) {
        double[] b = {1, -0.5};
        double[] a = {1, -0.8};
        int N = 100;
        double[] H = amplitudeResponse(b, a, N);
        for (int i = 0; i < N; i++) {
            double w = Math.PI * i / N;
            System.out.printf("%.3f %.3f\n", w, H[i]);
        }
    }
}


2. 相频特性曲线


相频特性曲线是指滤波器的输出信号相位与输入信号相位之差随着频率变化的曲线。相位响应通常用角度单位来表示,例如弧度或度数。下面是一个简单的Java代码示例,展示如何绘制相频特性曲线:

public class PhaseResponse {
    public static double[] phaseResponse(double[] b, double[] a, int N) {
        double[] Phi = new double[N];
        for (int i = 0; i < N; i++) {
            double w = Math.PI * i / N;
            Complex z = new Complex(Math.cos(w), Math.sin(w));
            Complex Hz = PolynomialUtils.evaluate(b, z).divide(PolynomialUtils.evaluate(a, z));
            Phi[i] = Hz.getArgument();
        }
        return Phi;
    }
    public static void main(String[] args) {
        double[] b = {1, -0.5};
        double[] a = {1, -0.8};
        int N = 100;
        double[] Phi = phaseResponse(b, a, N);
        for (int i = 0; i < N; i++) {
            double w = Math.PI * i / N;
            System.out.printf("%.3f %.3f\n", w, Phi[i]);
        }
    }
}


3. 群延迟曲线


群延迟曲线是指滤波器对不同频率的输入信号引起的信号延迟随着频率变化的曲线。群延迟是指信号在经过滤波器后的延迟时间与理想情况下通过相同滤波器所引起的延迟时间之间的差异。群延迟通常用时间单位来表示,例如秒或毫秒。下面是一个简单的Java代码示例,展示如何绘制群延迟曲线:

public class GroupDelay {
    public static double[] groupDelay(double[] b, double[] a, int N) {
        double[] H = new double[N];
        for (int i = 0; i < N; i++) {
            double w = Math.PI * i / N;
                        Complex z = new Complex(Math.cos(w), Math.sin(w));
            Complex Hz = PolynomialUtils.evaluate(b, z).divide(PolynomialUtils.evaluate(a, z));
            H[i] = -z.multiply(PolynomialUtils.differentiate(PolynomialUtils.log(Hz))).getReal();
        }
        return H;
    }
    public static void main(String[] args) {
        double[] b = {1, -0.5};
        double[] a = {1, -0.8};
        int N = 100;
        double[] G = groupDelay(b, a, N);
        for (int i = 0; i < N; i++) {
            double w = Math.PI * i / N;
            System.out.printf("%.3f %.3f\n", w, G[i]);
        }
    }
}


以上是滤波器的性能评价方法及其在Java中的实现。需要注意的是,这些曲线的绘制可能需要使用一些第三方库来辅助实现,例如Apache Commons Math、JFreeChart等。同时,在进行滤波器性能评价时,还需要考虑其他因素,例如滤波器的阶数、截止频率等,以综合评估滤波器的性能。


实际应用


了解滤波器在实际应用中的常见场景,如音频处理、图像处理、通信系统和控制系统等方面的应用。

滤波器在实际应用中广泛存在,涉及到许多领域,包括音频处理、图像处理、通信系统和控制系统等。下面简要介绍这些方面的应用,并给出相应的Java代码示例。


1. 音频处理


音频处理是指对声音信号进行处理的过程,常见应用包括音频增强、降噪、均衡等。滤波器在音频处理中广泛使用,例如高通滤波器可以用于去除低频噪声,低通滤波器可以用于去除高频噪声。下面是一个简单的Java代码示例,展示如何利用滤波器进行音频降噪:

public class AudioProcessor {
    public static void main(String[] args) throws UnsupportedAudioFileException, IOException {
        File input = new File("input.wav");
        AudioInputStream in = AudioSystem.getAudioInputStream(input);
        AudioFormat format = in.getFormat();
        int channels = format.getChannels();
        int sampleRate = (int)format.getSampleRate();
        double cutoffFrequency = 1000;
        double[] b = {1};
        double[] a = FilterDesign.designLowpassFilter(cutoffFrequency / sampleRate);
        IIRFilter filter = new IIRFilter(a, b);
        byte[] buffer = new byte[4096];
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int n = 0;
        while ((n = in.read(buffer)) != -1) {
            for (int i = 0; i < n; i += 2) {
                double x = (buffer[i] & 0xff) | ((buffer[i + 1] & 0xff) << 8);
                for (int j = 0; j < channels; j++) {
                    double y = filter.filter(x);
                    buffer[i + j * 2] = (byte)(y & 0xff);
                    buffer[i + j * 2 + 1] = (byte)((y >> 8) & 0xff);
                }
            }
            out.write(buffer, 0, n);
        }
        in.close();
        byte[] audioData = out.toByteArray();
        File output = new File("output.wav");
        AudioSystem.write(new AudioInputStream(new ByteArrayInputStream(audioData), format, audioData.length), AudioFileFormat.Type.WAVE, output);
    }
}


2. 图像处理


滤波器在图像处理中也经常用于去除噪声、平滑轮廓等操作。常见的滤波器包括均值滤波器、高斯滤波器、中值滤波器等。下面是一个简单的Java代码示例,展示如何利用滤波器进行图像平滑处理:

public class ImageProcessor {
    public static BufferedImage smooth(BufferedImage image, int kernelSize) {
        int width = image.getWidth();
        int height = image.getHeight();
        BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        int[][] kernel = createGaussianKernel(kernelSize);
        int k = kernelSize / 2;
        for (int i = k; i < width - k; i++) {
            for (int j = k; j < height - k; j++) {
                int rSum = 0, gSum = 0, bSum = 0;
                for (int u = -k; u <= k; u++) {
                    for (int v = -k; v <= k; v++) {
                        Color color = new Color(image.getRGB(i + u, j + v));
                        int kernelValue = kernel[k + u][k + v];
                        rSum += kernelValue * color.getRed();
                        gSum += kernelValue * color.getGreen();
                        bSum += kernelValue * color.getBlue();
                    }
                }
                int r = rSum / kernelSize / kernelSize;
                int g = gSum / kernelSize / kernelSize;
                int b = bSum / kernelSize / kernelSize;
                result.setRGB(i, j, new Color(r, g, b).getRGB());
            }
        }
        return result;
    }
    private static int[][] createGaussianKernel(int size) {
        double sigma = size / 6.0;
        int k = size / 2        int[][] kernel = new int[size][size];
        double sum = 0;
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                double x = i - k, y = j - k;
                double value = Math.exp(-(x * x + y * y) / (2 * sigma * sigma));
                kernel[i][j] = (int)Math.round(value * 255);
                sum += kernel[i][j];
            }
        }
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                kernel[i][j] = (int)Math.round(kernel[i][j] / sum);
            }
        }
        return kernel;
    }
    public static void main(String[] args) throws IOException {
        BufferedImage image = ImageIO.read(new File("input.jpg"));
        BufferedImage result = smooth(image, 5);
        ImageIO.write(result, "jpg", new File("output.jpg"));
    }
}


3. 通信系统


滤波器在通信系统中的应用非常广泛,例如用于解调、解码、降噪等操作。常见的滤波器包括低通滤波器、带通滤波器、高通滤波器等。下面是一个简单的Java代码示例,展示如何利用滤波器进行数字信号解调:

public class Demodulator {
    public static byte[] demodulate(byte[] signal, int sampleRate, double carrierFrequency) {
        double[] t = new double[signal.length / 2];
        double[] x = new double[t.length];
        for (int i = 0; i < t.length; i++) {
            t[i] = i * 1.0 / sampleRate;
            x[i] = (signal[i * 2] & 0xff) * Math.cos(2 * Math.PI * carrierFrequency * t[i]) - (signal[i * 2 + 1] & 0xff) * Math.sin(2 * Math.PI * carrierFrequency * t[i]);
        }
        double cutoffFrequency = 2000;
        double[] b = {1, -1};
        double[] a = FilterDesign.designHighpassFilter(cutoffFrequency / sampleRate);
        IIRFilter filter = new IIRFilter(a, b);
        byte[] result = new byte[x.length];
        for (int i = 0; i < x.length; i++) {
            double y = filter.filter(x[i]);
            result[i] = (byte)(y + 128);
        }
        return result;
    }
    public static void main(String[] args) throws IOException {
        byte[] signal = Files.readAllBytes(new File("signal.raw").toPath());
        int sampleRate = 44100;
        double carrierFrequency = 1000;
        byte[] data = demodulate(signal, sampleRate, carrierFrequency);
        FileOutputStream out = new FileOutputStream(new File("output.raw"));
        out.write(data);
        out.close();
    }
}


4. 控制系统


滤波器在控制系统中的应用也非常广泛,例如用于去除干扰、提取信号等操作。常见的滤波器包括带阻滤波器、陷波滤波器、低通滤波器等。下面是一个简单的Java代码示例,展示如何利用滤波器进行控制系统中的信号处理:

public class SignalProcessor {
    public static void main(String[] args) {
        double[] signal = {0.5, 1.2, 1.8, 2.5, 3.2, 4.1, 4.8, 5.5, 6.2, 6.9};
        double[] b = {1, -1};
        double[] a = {1, -0.8};
        IIRFilter filter = new IIRFilter(a, b);
        for (int i = 0; i < signal.length; i++) {
            double y = filter.filter(signal[i]);
            System.out.printf("%.2f %.2f\n", signal[i], y);
        }
    }
}


以上是滤波器在实际应用中的常见场景及其在Java中的实现,在控制系统中,我们还可以通过MATLAB和Simulink来进行更加高级的滤波器设计与应用。例如,下面是一个MATLAB代码示例,展示如何利用MATLAB进行带通滤波器设计:

fs = 1000; % 采样频率
f1 = 50; f2 = 150; % 带通频率范围
[b, a] = butter(5, [f1, f2]/(fs/2), 'bandpass'); % 设计带通滤波器
freqz(b, a); % 绘制幅度响应曲线


上述代码中,我们使用了MATLAB提供的butter函数,该函数可以根据指定的阶数和截止频率范围来设计滤波器系数。接着,我们使用freqz函数绘制了滤波器的幅度响应曲线。


与此类似,我们还可以利用Simulink进行滤波器的建模和仿真。例如,下面是一个简单的Simulink模型示例,展示了如何利用Simulink对音频信号进行低通滤波处理:

上述模型中,我们将输入音频信号通过一个低通滤波器进行处理,然后输出处理结果。在模型中,我们使用了Simulink提供的IIR Filter模块来实现低通滤波器,该模块可以根据指定的系数来进行滤波处理。在模拟过程中,我们可以对输入信号进行调整,观察滤波器的效果。


综上所述,滤波器在实际应用中有着广泛的应用场景,在不同的领域中都有不同的具体实现方式。通过掌握滤波器的基本概念和常见设计方法,以及利用MATLAB、Simulink等工具来进行高级应用,可以帮助我们更好地理解和应用滤波器。


高级主题


深入研究自适应滤波、多速率信号处理、小波变换和滤波器组等高级主题。


1. 自适应滤波


自适应滤波是一种能够根据输入信号的特性动态调整滤波器系数的滤波方法。它可以用于去除不同类型的噪声、提取难以分辨的信号等。常见的自适应滤波算法包括LMS算法和RLS算法。下面是一个简单的Java代码示例,展示如何利用LMS算法进行自适应滤波:

public class AdaptiveFilter {
    public static double[] lmsFilter(double[] input, double[] desired, int order, double mu) {
        double[] weights = new double[order];
        double[] output = new double[input.length];
        for (int i = 0; i < input.length; i++) {
            double y = 0;
            for (int j = 0; j < order; j++) {
                y += weights[j] * input[i - j];
            }
            output[i] = y;
            double error = desired[i] - y;
            for (int j = 0; j < order; j++) {
                weights[j] += mu * error * input[i - j];
            }
        }
        return output;
    }
    public static void main(String[] args) {
        double[] input = {1, -0.5, 0.2, -0.1, -0.3, 0.4, -0.6, 0.7, -0.8, 0.9};
        double[] noise = {0.1, -0.2, 0.3, -0.4, 0.5, -0.6, 0.7, -0.8, 0.9, -1};
        double[] desired = new double[input.length];
        for (int i = 0; i < input.length; i++) {
            desired[i] = input[i] + noise[i];
        }
        int order = 3;
        double mu = 0.05;
        double[] output = lmsFilter(input, desired, order, mu);
        System.out.println(Arrays.toString(output));
    }
}


2. 多速率信号处理


多速率信号处理是指对信号进行分带、抽取、插值等操作,以便于进行不同频率范围的处理。常见的多速率信号处理方法包括多解析度分析、数字滤波器组等。下面是一个简单的Java代码示例,展示如何利用数字滤波器组进行多速率信号处理:

public class MultirateSignalProcessing {
    public static double[] resample(double[] signal, int inRate, int outRate) {
        double[] result = new double[signal.length * outRate / inRate];
        double factor = (double)inRate / outRate;
        FIRFilter filter = FilterDesign.designLowpassFilter(0.45 / factor);
        int k = filter.size() / 2;
        for (int i = 0; i < result.length; i++) {
            double t = i * factor;
            int index = (int)Math.round(t);
            double sum = 0;
            for (int j = -k; j <= k; j++) {
                if (index + j >= 0 && index + j < signal.length) {
                    sum += filter.get(j + k) * signal[index + j];
                }
            }
            result[i] = sum;
        }
        return result;
    }
    public static void main(String[] args) {
        int inRate = 44100;
        int outRate = 22050;
        double[] signal = new double[inRate];
        for (int i = 0; i < signal.length; i++) {
            signal[i] = Math.sin(2 * Math.PI * 1000 * i / inRate);
        }
        double[] resampledSignal = resample(signal, inRate, outRate);
        System.out.println(Arrays.toString(resampledSignal));
    }
}


3. 小波变换


小波变换是一种能够在时域和频域之间进行转换的信号处理方法,它可以捕获信号的瞬时特性和局部特征。常见的小波变换包括离散小波变换和连续小波变换。下面是一个简单的Java代码示例,展示如何利用JWave库进行小波变换:

import jwave.Transform;
import jwave.transforms.FastWaveletTransform;
import jwave.transforms.wavelets.haar.Haar1;
public class WaveletTransform {
    public static double[] waveletTransform(double[] signal) {
        Transform transform = new FastWaveletTransform(new Haar1());
        double[] coefficients = transform.forward(signal);
        return coefficients;
    }
    public static double[] inverseWaveletTransform(double[] coefficients) {
        Transform transform = new FastWaveletTransform(new Haar1());
        double[] signal = transform.reverse(coefficients);
        return signal;
    }
    public static void main(String[] args) {
        double[] signal = {0.5, 1.2, 1.8, 2.5, 3.2, 4.1, 4.8, 5.5};
        double[] coefficients = waveletTransform(signal);
        System.out.println(Arrays.toString(coefficients));
        double[] reconstructedSignal = inverseWaveletTransform(coefficients);
        System.out.println(Arrays.toString(reconstructedSignal));
    }
}


4. 滤波器组


滤波器组是由多个滤波器组合而成的信号处理方法,常用于对不同频率范围的信号进行分离、分析等操作。常见的滤波器组包括小波变换滤波器组、多相滤波器组等。下面是一个简单的Java代码示例,展示如何利用多相滤波器组进行信号分离:

public class FilterBank {
    public static double[][] filterBank(double[] signal, FIRFilter[] filters) {
        double[][] output = new double[filters.length][signal.length];
        int k = filters[0].size() / 2;
        for (int i = 0; i < filters.length; i++) {
            FIRFilter filter = filters[i];
            for (int j = 0; j < signal.length; j++) {
                double sum = 0;
                for (int l = -k; l <= k; l++) {
                    if (j + l >= 0 && j + l < signal.length) {
                        sum += filter.get(l + k) * signal[j + l];
                    }
                }
                output[i][j] = sum;
            }
        }
        return output;
    }
    public static void main(String[] args) {
        double[] signal = {0.5, 1.2, 1.8, 2.5, 3.2, 4.1, 4.8, 5.5};
        FIRFilter[] filters = FilterDesign.designBandpassFilters(new double[]{0.3, 0.6}, new double[]{0.05, 0.1}, 10);
        double[][] output = filterBank(signal, filters);
        for (int i = 0; i < filters.length; i++) {
            System.out.println(Arrays.toString(output[i]));
        }
    }
}


以上是自适应滤波、多速率信号处理、小波变换和滤波器组等高级主题的概念及其在Java中的简单实现。这些主题涵盖了信号处理中的许多高级应用,通过深入研究这些主题,可以进一步提升我们的信号处理技能。


监听器


JavaWeb监听器是一种能够在特定事件发生时自动执行相应代码的组件。它可以用于监听Web应用程序的生命周期、会话状态变化、请求和响应等事件,以便于进行一些预处理或后续处理。下面是JavaWeb监听器的概念及其在Java中的详细实现。


1. 概念


JavaWeb监听器是一组Java类,它们能够监听特定事件(如Servlet的生命周期、Session的创建和销毁、ServletContext属性的修改等)并在事件发生时执行相应的代码。


监听器通常包含三个部分:事件源、事件监听器和事件处理器。事件源表示被监听的对象;事件监听器是一个实现了特定接口的Java类,用于接收和处理事件;事件处理器则是在事件监听器中定义的方法,用于对接收到的事件进行处理。


JavaWeb监听器主要有以下几种类型:


  • ServletContextListener:用于监听ServletContext的生命周期事件,如ServletContext的创建和销毁。
  • ServletRequestListener和ServletRequestAttributeListener:用于监听HttpServletRequest的生命周期事件,如ServletRequest的创建和销毁,以及ServletRequest中属性的修改。
  • HttpSessionListener和HttpSessionAttributeListener:用于监听HttpSession的生命周期事件,如HttpSession的创建和销毁,以及HttpSession中属性的修改。


2. Java代码详解


下面是一个简单的JavaWeb监听器的示例,展示如何使用ServletContextListener监听ServletContext的生命周期事件:

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener {
    public void contextInitialized(ServletContextEvent event) {
        System.out.println("ServletContext创建");
    }
    public void contextDestroyed(ServletContextEvent event) {
        System.out.println("ServletContext销毁");
    }
}


在上述示例中,我们定义了一个MyServletContextListener类,并实现了ServletContextListener接口。其中的contextInitialized和contextDestroyed方法分别对应ServletContext的创建和销毁事件,它们会在相应事件发生时自动被调用。


接下来,在web.xml文件中配置监听器:

<listener>
    <listener-class>MyServletContextListener</listener-class>
</listener>


这样,在应用程序启动时,就会自动创建一个ServletContext对象,并触发MyServletContextListener的contextInitialized方法;而在应用程序关闭时,就会自动销毁ServletContext对象,并触发MyServletContextListener的contextDestroyed方法。


除了ServletContextListener外,其他类型的监听器也可以通过类似的方式进行配置。


总之,JavaWeb监听器是一种能够自动监听特定事件并执行相应代码的组件,它可以用于监听Web应用程序的生命周期、会话状态变化、请求和响应等事件,以便于进行一些预处理或后续处理。


AjaxAjax


Ajax(Asynchronous JavaScript and XML)是一种在Web页面上异步加载数据的技术,通过JavaScript和XMLHttpRequest对象实现。它可以使Web应用程序更加流畅地响应用户操作,而无需刷新整个页面。


1. 实现原理


Ajax的实现原理主要包括以下几个步骤:


在Web页面中,使用JavaScript创建XMLHttpRequest对象。

使用XMLHttpRequest对象向服务器发送HTTP请求,并指定要获取的数据类型(如文本、XML、JSON等)以及请求参数。

服务器端接收到请求后,处理请求并将结果以指定的数据类型返回给客户端。

客户端接收到服务器返回的数据后,使用JavaScript对页面进行动态更新,无需刷新整个页面。


2. 优点


与传统的Web页面相比,Ajax技术具有以下几个优点:


提高了用户体验。使用Ajax技术能够使Web应用程序更加流畅地响应用户操作,提高了用户体验。

减少了网络带宽的占用。由于Ajax可以部分更新Web页面,因此减少了不必要的数据传输,降低了网络带宽的占用。

提高了Web应用程序的性能。使用Ajax可以避免重复加载Web页面,减少不必要的服务器负荷,提高Web应用程序的性能。

提高了代码的可维护性。使用Ajax技术可以让Web应用程序的代码更加简洁、清晰,提高了代码的可维护性。


3. 实现方式


Ajax技术可以使用原生的JavaScript实现,也可以使用常见的JavaScript库(如jQuery、Prototype等)来简化编码。下面是一个基于原生JavaScript实现的简单Ajax示例:

var xmlhttp;
if (window.XMLHttpRequest) {
    // IE7+、Firefox、Chrome、Opera、Safari支持XMLHttpRequest对象
    xmlhttp = new XMLHttpRequest();
} else {
    // IE6、IE5支持ActiveXObject对象
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        // 当readyState为4且status为200时,表示请求成功
        document.getElementById("myDiv").innerHTML = xmlhttp.responseText;
    }
}
// 向服务器发送GET请求,并指定URL、异步标志为true
xmlhttp.open("GET", "ajax_info.txt", true);
xmlhttp.send();


在上述示例中,我们首先创建了一个XMLHttpRequest对象,并通过它向服务器发送了一个异步的GET请求。当服务器返回数据后,我们将其显示在名为"myDiv"的页面元素中。


4. 总结


Ajax是一种通过JavaScript和XMLHttpRequest对象实现异步加载数据的技术,能够提高Web应用程序的响应速度和用户体验。它可以使用原生的JavaScript实现,也可以使用常见的JavaScript库来简化编码。

相关文章
|
2月前
|
Web App开发 SQL Java
javaweb实现分页(二)
javaweb实现分页(二)
19 1
|
2月前
|
SQL 关系型数据库 MySQL
javaweb实现分页查询(一)
javaweb实现分页查询(一)
20 0
|
2月前
|
SQL 关系型数据库 MySQL
javaweb中实现分页,持续更新……
javaweb中实现分页,持续更新……
19 1
|
28天前
|
JSON Java 应用服务中间件
JavaWeb项目之乱码问题及如何解决
JavaWeb项目之乱码问题及如何解决
|
2月前
|
Java Spring 容器
[JavaWeb]——过滤器filter与拦截器Interceptor的使用、执行过程、区别
[JavaWeb]——过滤器filter与拦截器Interceptor的使用、执行过程、区别
|
2月前
JavaWeb 开发之 ServletContext 的和使用
JavaWeb 开发之 ServletContext 的和使用
23 1
|
23天前
|
JavaScript 前端开发
javaweb文件上传和下载
javaweb文件上传和下载
|
2月前
|
前端开发 NoSQL 应用服务中间件
javaweb单点登录的三种实现方式
javaweb单点登录的三种实现方式
35 0
|
2月前
|
SQL 前端开发 Java
Java后端进阶之路: JavaWeb(四)
Java后端进阶之路: JavaWeb
35 1
|
XML SQL Java
Java后端进阶之路: JavaWeb(三)
Java后端进阶之路: JavaWeb
34 1