零基础学习java------day27-28---------电影评分数据案例,. RPC案例
一. 电影评分数据案例
movie:电影id
rate:用户评分
timeStamp:评分时间
uid:用户id
简化数据:
需求:
(1)每个用户评分最高的3部电影
(2)每个用户评分的平均值
(3)最大方(评分平均值高)的N个用户
(4)最热门的N部电影(评论次数)
(5)评价最高的N部电影
代码(此处只写了1-3题,剩下的类似的写)
工具类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class LoadDataUtils { /** * 以用户id分组 */ public static Map<String, List<Movie>> getUidMap(){ Map<String, List<Movie>> uidMap = new HashMap<>(); // 获取缓冲字符流 try ( BufferedReader br = new BufferedReader(new FileReader("E:/javafile/movie.txt")); ){ String line = null; while((line = br.readLine()) != null) { // 获取movie对象 Movie m = JSON.parseObject(line, Movie.class); String uid = m.getUid(); List<Movie> list = uidMap.getOrDefault(uid, new ArrayList<Movie>()); list.add(m); //将数据封装进uidMap uidMap.put(uid,list); } } catch (Exception e) { e.printStackTrace(); } return uidMap; } /** * 以movie分组 * @return */ public static Map<String, List<Movie>> getMovieMap(){ Map<String, List<Movie>> movieMap = new HashMap<>(); // 获取缓冲字符流 try ( BufferedReader br = new BufferedReader(new FileReader("E:/javafile/movie.txt")); ){ String line = null; while((line = br.readLine()) != null) { Movie m = JSON.parseObject(line, Movie.class); String mid = m.getMovie(); List<Movie> list = movieMap.getOrDefault(mid, new ArrayList<Movie>()); list.add(m); movieMap.put(mid,list); } } catch (Exception e) { e.printStackTrace(); } return movieMap; } }
实现类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class MovieTest1 { public static void main(String[] args) { // movieTop3OfEveryone(); // avrgOfEveryone(); userRateTop3(); } // 每个用户评分最高的3部电影 public static void movieTop3OfEveryone() { Map<String, List<Movie>> uidMap = LoadDataUtils.getUidMap(); System.out.println(uidMap); Set<Entry<String, List<Movie>>> entrySet = uidMap.entrySet(); for (Entry<String, List<Movie>> entry : entrySet) { List<Movie> list = entry.getValue(); if(list !=null && list.size() >= 3) { Collections.sort(list, new Comparator<Movie>() { @Override public int compare(Movie o1, Movie o2) { return (o1.getRate()>o2.getRate())?-1:1; } }); for (int i=0;i<3; i++) { Movie m = list.get(i); System.out.println(entry.getKey()+":"+m); } } } } // 每个用户评分的平均值 public static void avrgOfEveryone() { Map<String, List<Movie>> uidMap = LoadDataUtils.getUidMap(); Set<Entry<String, List<Movie>>> entrySet = uidMap.entrySet(); for (Entry<String, List<Movie>> entry : entrySet) { List<Movie> list = entry.getValue(); double total = 0; for(Movie movie : list) { total += movie.getRate(); } double avrg = total/list.size(); System.out.println(entry.getKey()+"电影评分的平均分为:"+avrg); } } // 最大方(评分平均值高)的N个用户 public static void userRateTop3() { Map<String, List<Movie>> uidMap = LoadDataUtils.getUidMap(); HashMap<String, Double> map = new HashMap<>(); Set<Entry<String, List<Movie>>> entrySet = uidMap.entrySet(); for (Entry<String, List<Movie>> entry : entrySet) { List<Movie> list = entry.getValue(); double total = 0; for(Movie movie : list) { total += movie.getRate(); } double avrg = total/list.size(); map.put(entry.getKey(), avrg); } Set<Entry<String, Double>> entrySet1 = map.entrySet(); ArrayList<Entry<String, Double>> list = new ArrayList<>(entrySet1); Collections.sort(list, new Comparator<Entry<String, Double>>() { @Override public int compare(Entry<String, Double> o1, Entry<String, Double> o2) { return o1.getValue()>o2.getValue()?-1:1; } }); for(int i = 0;i<3;i++) { System.out.println(list.get(i)); } } }
二. RPC案例
RPC(Remote Procedure Call)-远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果
案例:
客户端远程请求注册,登录服务端,服务端响应客户端登录和注册是否成功(获取信息分为从数据库中获取和从本地磁盘中获取)
大致思路图:
流程:客户端请求(即发送request请求对象)服务端(登录或者注册),请求中包含的信息为请求所要调用的方法,方法参数列表(形参),方法的全类名以及实参。客户端为了接受这个请求(request对象),其要在服务端创建一个一样的request去接收客户端请求中的参数(注意;全类名也要一样)。接着使用反射的方法调用该请求中的方法(此处不用new的形式来创建对象并调用方法,若业务区有多个方法,就需要new很多对象,消耗性能)。方法中包含了与数据库或是磁盘文件的交互,一般与数据库的交互是通过dao,所以业务区通过dao层与数据库或是磁盘文件交互。最终响应由dao层返回业务区,再返回给server端,最终客户端读取服务端的响应,即可拿到响应数据(登录或是注册是否成功)。
代码:
客户端:
项目构造:
MyClient代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class MyServer { @SuppressWarnings("resource") public static void main(String[] args) throws Exception { System.out.println("开始服务"); ServerSocket serverSocket = new ServerSocket(7788); while(true) { Socket socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); ObjectInputStream ois = new ObjectInputStream(inputStream); System.out.println("开始读取数据"); // 获取调用方法必须的参数 Request request = (Request)ois.readObject(); System.out.println("数据读取完毕"); String className = request.getClassName(); String methodName = request.getMethodName(); Class<?>[] parameterTypes = request.getParameterTypes(); Object[] paraterValues = request.getParaterValues(); // 反射调用方法,并接收返回数据 Class<?> clazz = Class.forName(className); Method method = clazz.getMethod(methodName, parameterTypes); Response response = (Response)method.invoke(clazz.newInstance(), (User)paraterValues[0]); System.out.println("接收数据完毕"); // 向客户端发送响应 ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); oos.writeObject(response); System.out.println(response); oos.close(); ois.close(); socket.close(); } } }
POJO(简单java对象,一般是由私有属性以及相应的设置或者获取这些属性的方法构成)部分代码:
request
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class Request implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String className; private String methodName; private Class<?>[] parameterTypes; private Object[] paraterValues; public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public Class[] getParameterTypes() { return parameterTypes; } public void setParameterTypes(Class[] parameterTypes) { this.parameterTypes = parameterTypes; } public Object[] getParaterValues() { return paraterValues; } public void setParaterValues(Object[] paraterValues) { this.paraterValues = paraterValues; } @Override public String toString() { return "Request [className=" + className + ", methodName=" + methodName + ", parameterTypes=" + Arrays.toString(parameterTypes) + ", paraterValues=" + Arrays.toString(paraterValues) + "]"; } }
response:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class Response implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String msg; private String statusCode; private User user; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String getStatusCode() { return statusCode; } public void setStatusCode(String statusCode) { this.statusCode = statusCode; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String toString() { return "Response [msg=" + msg + ", statusCode=" + statusCode + ", user=" + user + "]"; } }
User:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class User implements Serializable{ /** * */ private static final long serialVersionUID = 1L; String name; int age; String password; public User() { } public User(String name, int age, String password) { super(); this.name = name; this.age = age; this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User [name=" + name + ", age=" + age + ", password=" + password + "]"; }
服务端(server):
Myserver
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class MyServer { @SuppressWarnings("resource") public static void main(String[] args) throws Exception { System.out.println("开始服务"); ServerSocket serverSocket = new ServerSocket(7788); while(true) { Socket socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); ObjectInputStream ois = new ObjectInputStream(inputStream); System.out.println("开始读取数据"); // 获取调用方法必须的参数 Request request = (Request)ois.readObject(); System.out.println("数据读取完毕"); String className = request.getClassName(); String methodName = request.getMethodName(); Class<?>[] parameterTypes = request.getParameterTypes(); Object[] paraterValues = request.getParaterValues(); // 反射调用方法,并接收返回数据 Class<?> clazz = Class.forName(className); Method method = clazz.getMethod(methodName, parameterTypes); Response response = (Response)method.invoke(clazz.newInstance(), (User)paraterValues[0]); System.out.println("接收数据完毕"); // 向客户端发送响应 ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); oos.writeObject(response); System.out.println(response); oos.close(); ois.close(); socket.close(); } } }
业务区(service)
UserServer(接口)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public interface UserServer { /** * 用于用户登录 * @param user * @return * @throws Exception */ public Response login(User user) throws Exception; /** * 用于用户的注册 * @param user * @return * @throws Exception */ public Response register(User user) throws Exception; }
UserServerImpl(实现注册和登录)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class UserServerImpl implements UserServer{ // 使用静态代码块加载配置文件 static String className; static UserDao userDao; static { try { Properties p = new Properties(); p.load(UserServerImpl.class.getClassLoader().getResourceAsStream("class.properties")); className = p.getProperty("className"); userDao = (UserDao)Class.forName(className).newInstance(); } catch (Exception e) { e.printStackTrace(); } } // 为了提高代码的扩展性,使用配置文件并使用反射获取实例对象 // 实现登录 @Override public Response login(User user) throws Exception { System.out.println(user); User user1 = userDao.getUserFromDbByNameAndPwd(user); Response response = new Response(); System.out.println(user1); // 登录失败 if(user1==null) { response.setMsg("登录失败"); response.setStatusCode("500"); response.setUser(null); }else { response.setMsg("登录成功"); response.setStatusCode("200"); response.setUser(user1); } return response; } // 实现注册 @Override public Response register(User user) throws Exception { Response response = new Response(); boolean b = userDao.insertMessageOfUser(user); if(b){ response.setMsg("注册成功"); response.setStatusCode("200"); }else{ response.setMsg("注册失败"); response.setStatusCode("500"); } return response; } }
dao
UserDao(接口)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public interface UserDao { /** * 根据用户名和密码从数据库中查询用户 * @param name * @param password * @return */ public User getUserFromDbByNameAndPwd(User user) throws Exception; /** * 往数据库插入数据 * @param user * @return */ public boolean insertMessageOfUser(User user) throws Exception; }
UserDaoImpl1(与磁盘文件交互)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 操作文件 * @author ASUS * */ public class UserDaoImpl1 implements UserDao{ @Override public User getUserFromDbByNameAndPwd(User u) throws Exception { Map<String, User> map = TestMyUtil.getUserFromFile(); User user = null; if(map != null) { user = map.get(u.getName()); if(user !=null) { String pwd = user.getPassword(); if(u.getPassword().equals(pwd)) { return user; } } } return user; } @SuppressWarnings("unchecked") @Override public boolean insertMessageOfUser(User user) throws Exception { Map<String, User> map =null ; File f = new File(Const.PATH); boolean result = false; if(!f.exists()) { //文件不存在,直接存map map = new HashMap<>(); map.put(user.getName(), user); FileUtil.addObjectToFile(map, Const.PATH); result = true; // 文件已经存在,则先取出文件中的map对象,再存入相应的数据 }else { // 取出map map = (Map<String, User>) FileUtil.getObjectFromFile(Const.PATH); boolean b = map.containsKey(user.getName()); if(!b) { // 将数据存入已存在的map中,并将之写入文件 map.put(user.getName(), user); FileUtil.addObjectToFile(map, Const.PATH); result = true; } } return result; } }
UserDaoImpl2
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 操作数据库 * @author ASUS * */ public class UserDaoImpl2 implements UserDao{ static ComboPooledDataSource dataSource; static QueryRunner runner; static { // 获取连接池对象,其中包含连接数据库所需要的参数 dataSource = new ComboPooledDataSource(); // 连接数据库 runner = new QueryRunner(dataSource); } // 查询数据 @Override public User getUserFromDbByNameAndPwd(User u) throws Exception { String sql = "select * from user where name=?and password=?"; User user = runner.query(sql, new BeanHandler<>(User.class),u.getName(),u.getPassword()); return user; } // 插入数据 @Override public boolean insertMessageOfUser(User u) throws Exception { String sql = "insert into user values(?,?,?)"; int i = runner.update(sql,u.getName(),u.getAge(),u.getPassword()); if(i>0) { return true; } return false; } }
工具类(utils)
Const(保证操作的路径一致)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 指定路径 * @author ASUS * */ public class Const { public static final String PATH = "E:/javafile/object.txt"; }
FileUtil
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 1 读取指定文件 获取对象 * 2 向指定文件中存储对象 * @author ASUS * */ public class FileUtil { /** * 读取指定文件 获取对象 * @param path * @return * @throws Exception */ public static Object getObjectFromFile(String path) throws Exception { File f = new File(path); Object obj = null ; if(f.exists()){ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f)); obj = ois.readObject(); ois.close(); } return obj; } /** * 向指定文件中存储对象 * @param obj * @param path * @throws Exception */ public static void addObjectToFile(Object obj , String path) throws Exception{ File f = new File(path); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f)); oos.writeObject(obj); oos.close(); } }