会员可以在此提问,百战程序员老师有问必答
对大家有帮助的问答会被标记为“推荐”
看完课程过来浏览一下别人提的问题,会帮你学得更全面
截止目前,同学们一共提了 132647个问题

老师,您好,我在这里遇到了问题

问题描述:在进行Reseponse封装后,服务器能启动起来,但在html文档里面输入内容后登录服务器空指针异常。

相关代码

Response

package cn.bjsxt.server;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;

import com.bjsxt.util.IOCloseUtil;

public class Response {/*响应*/
	private StringBuilder headInfo;//响应头
	private StringBuilder content;//响应内容
	private int length;//响应内容的长度
	//流
	private BufferedWriter bw;
	//两个常量,换行和空格
	private static final String CRLF="\r\n";//换行
	private static final String BLANK=" ";//空格
	//构造方法
	public Response(){
		headInfo = new StringBuilder();
		content = new StringBuilder();
	}
	//带参构造方法
	public Response(OutputStream os){
		this();//调用本类的无参构造方法
		try {
			bw=new BufferedWriter(new OutputStreamWriter(os,"utf-8"));//初始化输出流
		} catch (UnsupportedEncodingException e) {
			headInfo=null;
		}
	}
	//构造正文部分
	public Response print(String info){
		content.append(info);
		try {
			length+=info.getBytes("uft-8").length;
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return this;
	}
	public Response println(String info){
		content.append(info).append(CRLF);
		try {
			length+=(info+CRLF).getBytes("utf-8").length;
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	return this;
	}
	//构造响应头
	private void createHeadInfo(int code){
		headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);
		switch(code){
		case 200:
			headInfo.append("OK");
			break;
		case 500:
			headInfo.append("SERVER ERROR");
			break;
		default:
			headInfo.append("NOT FOUND");
			break;
		
		}
		headInfo.append(CRLF);
		headInfo.append("Content-Type:text/html;charset=utf-8").append(CRLF);
		headInfo.append("Content-Length:"+length).append(CRLF);
		headInfo.append(CRLF);
		
	}
	/**
	 * 推送到客户级的浏览器
	 * */
	public void pushToClient(int code){
		if(headInfo==null){
			code=500;
		}
		try{
			//调用笨了中的构造响应头
			this.createHeadInfo(code);
			bw.write(headInfo.toString());
			bw.write(content.toString());
			bw.flush();
			this.close();
		}catch(IOException e){
			e.printStackTrace();
		}
		
	}
	public void close(){
		IOCloseUtil.closeAll(bw);
	}

}

Server

package cn.bjsxt.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import com.bjsxt.servlet.Servlet;
import com.bjsxt.util.IOCloseUtil;

public class Server {//服务器,启动和停止服务
	private ServerSocket server;
	public static void main(String[] args){
		Server server = new Server();//创建服务器对象
		server.start();
	}
	public void start(int port){
		try {
			server = new ServerSocket(port);
			this.receive();//调用接收请求信息的方法
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public void start(){
		this.start(8888);
	}
	private void receive() {
		
		try {
			//(1)监听
			Socket client = server.accept();
			//封装请求信息
			
			Request req = new Request(client.getInputStream());
			/*	StringBuilder sb = new StringBuilder();
			sb.append("HTTP/1.1").append(" ").append(200).append(" ").append("OK").append("\r\n");//响应头
			sb.append("Content-Type:text/html;charset=utf-8").append("\r\n");//内容文本,编码格式
			//内容
			
			String str="<html><head><title>响应结果</title></head><body>成功</body></html>";
			
			sb.append("Content-Length:"+str.getBytes("utf-8").length).append("\r\n");
			sb.append("\r\n");
			sb.append(str);
			//通过输出流发送出去
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"utf-8"));
			bw.write(sb.toString());
			bw.flush();
			bw.close();*/
		/**
		 * 做出响应
		 * */
		Response rep=new Response(client.getOutputStream());
		Servlet servlet=WebApp.getServlet(req.getUrl());
		int code=200;
		if(servlet==null){
			code=404;
		}
		try {
			servlet.service(req,rep);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		rep.pushToClient(code);
		IOCloseUtil.closeAll(client);
		
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	}
	public void stop(){
		
	}

}

Request

package cn.bjsxt.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Request {/*请求*/
	private InputStream is;//输入流
	private String requestInfo;//请求字符串,请求方式,请求路径,参数,协议,协议版本,请求正文。。。
	private String method;//请求的方式
	private String url;//请求的url
	public String getUrl() {
		return url;
	}	

	//输入框的name为key,值为value
	/*
	 * key: username            value:bjsxt
	 * key: pwd                 value:123
	 * key: hobby               value:read,ball
	 * */
	private Map<String,List<String>> parametermapValues;//参数
	private static final String CRLF="\r\n";//换行
	private static final String BLANK=" ";//空格
	//构造方法,初始化属性
	public Request(){
		parametermapValues=new HashMap<String,List<String>>();
		method="";
		url="";
		requestInfo="";
		
	}
	public Request(InputStream is){
		this();//调用本类无参的构造方法
		this.is=is;
		try {
			byte[] buf=new byte[20480];
			int len=this.is.read(buf);
			requestInfo=new String(buf,0,len);
		} catch (IOException e) {
			return;
		}
		//调用本类中的分解请求信息的方法
		this.parseRequestInfo();
	}
	//分解请求信息的方法
	/**
	 * 请求路径
	 * 请求方式
	 * 请求参数
	 * */
	private void parseRequestInfo(){
		String paraString="";//用于储存请求参数
		//获取请求参数的第一行
		String firstLine=requestInfo.substring(0,requestInfo.indexOf(CRLF)).trim();//从0,到第一行换行
		//分解出请求方式
		int index=firstLine.indexOf("/");
		this.method=firstLine.substring(0,index).trim();//获去0到第一个“/”的数据
		//分解url ,get可能包含参数,也有可能不包含参数post
		String urlString = firstLine.substring(index,firstLine.indexOf("HTTP/")).trim();
		//判断请求方式是GET还是POST
		if("get".equalsIgnoreCase(this.method)){//包含请求参数
			if(urlString.contains("?")){//?之前是路径,之后是参数
				String [] urlArray=urlString.split("\\?");//使用?分离路径与参数
				this.url=urlArray[1];
				paraString=urlArray[1];
			}else{ //post不包含请求参数
				this.url=urlString;				
			}			
		}else{//post不包含请求参数
			this.url=urlString;
			paraString=requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();//获取最后一行
		}
		if(paraString.equals("")){
			return;
		}
		//请求参数
		//System.out.println(paraString);
		//调用本类中分解请求参数的方法
		this.parseParam(paraString);
	}
	//根据表单元素的name获取多个值
	public String [] getParamterValues(String name){
		//根据key获取value
		List<String> values=parametermapValues.get(name);
		if(values==null){
			return null;
		}else{
			return values.toArray(new String [0]);
		}
	}
	//根据表单元素获的name获取单个值
	public String  getParameter(String name){
		//调用本类中根据name获取多个值的方法
		String [] values=getParamterValues(name);
		if((values==null)){
			return null;
		}else{
			return values[0];
		}
    }
	/*public void show(){
		System.out.println(this.url);
		System.out.println(this.method);
	}*/
	//username=bjsxt&pwd=123&hobby=ball&hobby=paint
	/**
	 * username=bjsxt
	 * pwd123
	 * hobby=ball
	 * 
	 * username=
	 * */

	private void parseParam(String prarString){
		String [] token = prarString.split("&");
		for(int i=0;i<token.length;i++){
			String keyValues=token[i];
			String [] keyValue=keyValues.split("=");//username bjsxt pwd 123
			if(keyValue.length==1){ //username=
				keyValue=Arrays.copyOf(keyValue, 2);
				keyValue[1]=null;
				
			}
			//将表单元素的name与name对应的值储存到Map集合
			String key=keyValue[0].trim();
			String value=keyValue[1]==null?null:decode(keyValue[1].trim(),"utf-8");
			//放到集合中储存
			if(!parametermapValues.containsKey(key)){//如果键不存在,去创建
				parametermapValues.put(key, new ArrayList<String>());			
			}//如果键存在,将值添加进来
			List<String> values=parametermapValues.get(key);
			values.add(value);
		}
		
	}


		
	public static void main(String[] args){
		Request req = new Request();
		//调用分解参数的方法
		req.parseParam("username=%E5%8C%97%E4%BA%AC%E5%B0%9A%E5%AD%A6%E5%A0%82&pwd=123&hobby=ball&hobby=paint");
		Map<String,List<String>> map=req.parametermapValues;
		Set<String>key=map.keySet();
		for (String string : key) {
			System.out.println(string+"\t"+map.get(string));
		
		}
    }
	//处理中文,因为浏览器对中文进行了编码,进行解码
	private String decode(String value,String code){
		try {
			return URLDecoder.decode(value,code);
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
}


运行图

image.png

代码包

http_server4.rar


JAVA 全系列/第二阶段:JAVA 基础深化和提高/手写服务器项目(旧) 3766楼

老师,该如何理解:序列化不能保存任何成员方法和静态的成员变量 

对此我还特意去写了一下

源码:

    自定义一个可以序列化的类除了get set 方法 还特意加了两个测试方法:

package com.sxt.obj;


import java.io.Serializable;

public class Student implements Serializable{
	private int id;
	private String name;
	public Student(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public Student() {
		super();
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String returntest() {//增加测试方法
		return "return ...";
	}
	public void voidTest() {//增加测试方法
		System.out.println("void ....");
	}
}

    2、写入

package com.sxt.obj;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class StudentWrite {
	public static void main(String[] args) {
		Student stu = new Student(1001, "张三");
		ObjectOutputStream oos = null;
		try {
			oos = new ObjectOutputStream(
					new BufferedOutputStream(
							new FileOutputStream("student.txt")));
			oos.writeObject(stu);
			oos.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(oos != null) {
				try {
					oos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

    3、读取

package com.sxt.obj;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class StudnentRead {
	public static void main(String[] args) throws ClassNotFoundException {
		ObjectInputStream ois = null;
		try {
			ois = new ObjectInputStream(
					new BufferedInputStream(
							new FileInputStream("student.txt")));
			Student stu = (Student) ois.readObject();
			String str = stu.returntest();
			System.out.println(str);
			stu.voidTest();
			System.out.println(stu.getId() + ", " + stu.getName());
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(ois != null) {
				try {
					ois.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
}


读取后还是可以使用对象的方法

image.png

源码:

ObjStreamPro.7z


最后,感觉方法还是保存了???

JAVA 全系列/第二阶段:JAVA 基础深化和提高/IO 流技术(旧) 3771楼
JAVA 全系列/第二阶段:JAVA 基础深化和提高/多线程技术(旧) 3772楼
JAVA 全系列/第二阶段:JAVA 基础深化和提高/常用类 3773楼

老师,在生产者消费者模式里面,wait和notify是不是都要在Good里面呢,我写在Producer和Consumer里好像就不起作用了,为什么?代码如下:

package com.produceandcomsume;

public class Goods {
	boolean isEmpty;
	private String name;
	private String brand;
	public Goods(String name, String brand) {
		super();
		this.name = name;
		this.brand = brand;
	}
	public Goods() {
		super();
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getBrand() {
		return brand;
	}
	public void setBrand(String brand) {
		this.brand = brand;
	}

}
package com.produceandcomsume;

class Producer implements Runnable {
	Goods good;
	public Producer(Goods good) {
		this.good = good;
	}
	@Override
	public void run() {
		producer();
	}
	public synchronized void producer() {
		if(!good.isEmpty) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for (int i = 0; i < 10; i++) {
			if (i % 2 == 0) {
				good.setBrand("娃哈哈");
				try {
					Thread.sleep(300);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				good.setName("矿泉水");
				System.out.println(Thread.currentThread().getName() + "生产了-->" + good.getBrand() + good.getName());
			} else {
				good.setBrand("旺仔");
				good.setName("小馒头");
				System.out.println(Thread.currentThread().getName() + "生产了-->" + good.getBrand() + good.getName());
			}
			super.notifyAll();
			good.isEmpty = false;
		}
	}
}
package com.produceandcomsume;

public class Consumer implements Runnable {
	Goods good;
	public Consumer(Goods good) {
		this.good = good;
	}
	@Override
	public void run() {
		consume();
	}
	public synchronized void consume() {
		if(good.isEmpty) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for (int i = 0; i < 10; i++) {
			good.getBrand();
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			good.getName();
			System.out.println(Thread.currentThread().getName() + "消费了-->" + good.getBrand() + good.getName());
		}
		super.notifyAll();
		good.isEmpty = true;
	}
}
package com.produceandcomsume;

public class Demo {
	public static void main(String[] args) {
		Goods goods = new Goods();
		goods.isEmpty = true;
		Thread producer = new Thread(new Producer(goods), "生产者");
		Thread consumer = new Thread(new Consumer(goods), "消费者");
		producer.start();
		consumer.start();
	}
}

运行结果:

image.png

JAVA 全系列/第二阶段:JAVA 基础深化和提高/多线程技术(旧) 3775楼
JAVA 全系列/第二阶段:JAVA 基础深化和提高/容器(旧) 3776楼

问题一:Server运行,游览器无响应啊?

问题二:StringBuilder sb,添加了那么多字符串的意义在哪里,响应只显示“成功”,其余的是被游览器解析的吗?

package cn.bjsxt.server;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {//服务器,启动和停止服务
	private ServerSocket server;
	public static void main(String[] args){
		Server server = new Server();//创建服务器对象
		server.start();
	}
	public void start(int port){
		try {
			server = new ServerSocket(port);
			this.receive();//调用接收请求信息的方法
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public void start(){
		this.start(8888);
	}
	private void receive() {
		
		try {
			//(1)监听
			Socket client = server.accept();
			//获取用户的请求
			/*InputStream is = client.getInputStream();
			byte [] buf = new byte[20480];
			int len = is.read(buf);
			System.out.println(new String(buf,0,len));*/
			Request req = new Request(client.getInputStream());
			//req.show();
			/**做出响应*/
			StringBuilder sb = new StringBuilder();
			sb.append("HTTP/1.1").append(" ").append(200).append(" ").append("OK").append("\r\n");
			sb.append("Content-Type:text/html;charset=utf-8").append("\r\n");
			//内容
			String str="<html><head><title>响应结果</ritle></head><body>成功</body></html>";
			sb.append("Content-Length:"+str.getBytes("utf-8").length).append("/r/n");
			sb.append("\r\n");
			sb.append(str);
			//通过输出流发送出去
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"utf-8"));
			bw.write(sb.toString());
			bw.flush();
			bw.close();
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public void stop(){
		
	}

}

image.png

http_server4.rar


JAVA 全系列/第二阶段:JAVA 基础深化和提高/手写服务器项目(旧) 3778楼
JAVA 全系列/第二阶段:JAVA 基础深化和提高/XML 技术(旧) 3779楼

课程分类

百战程序员微信公众号

百战程序员微信小程序

©2014-2025百战汇智(北京)科技有限公司 All Rights Reserved 北京亦庄经济开发区科创十四街 赛蒂国际工业园
网站维护:百战汇智(北京)科技有限公司
京公网安备 11011402011233号    京ICP备18060230号-3    营业执照    经营许可证:京B2-20212637